Reviews
Chapter 2
01. What are the modules of C++ programs called?
They are called functions02. What does the following preprocessor directive do?
It causes the contents of the iostream file to be substituted for this directive before final compilation.03. What does the following statement do?
It makes definitions made in the std namespace available to a program.04. What statement would you use to print the phrase “Hello, world” and then start a new line?
or
07. What statement would you use to read a value from keyboard input into the
variable cheeses ?
08. What statement would you use to print “We have X varieties of cheese,”
where the current value of the cheeses variable replaces X ?
09. What do the following function prototypes tell you about the functions?
The function froop() expects to be called with one argument, which will be type double, and that the function will return a type int value. For instance, it could be used as follows: int gval = froop(3.14159); The function rattle() has no return value and expects an int argument. For instance, it could be used as follows:
rattle(37); The function prune() returns an int and expects to be used without an argument. For instance, it could be used as follows:
int residue = prune(); 10. When do you not have to use the keyword return when you define a function?
You don’t have to use return in a function when the function has the return typevoid. However, you can use it if you don’t give a return value: return;
11. Suppose your main() function has the following line: And suppose the compiler complains that cout is an unknown identifier. What is the likely cause of this complaint, and what are three ways to fix the problem?
Lack of caller for std library. Use directive: or for onlycout or call library with std::cout instead of cout
Chapter 3
01. Why does C++ have more than one integer type?
Having more than one integer type lets you choose the type that is best suited to a particular need. For example, you could useshort to conserve space or long
to guarantee storage capacity or to find that a particular type speeds up a
particular calculation.
02. Declare variables matching the following descriptions:
      a. A short integer with the value 80
      b. An unsigned int integer with the value 42, 110
      c. An integer with the value 3, 000, 000, 000
short rbis = 80; // or short int rbis = 80;
unsigned int q = 42110; // or unsigned q = 42110;
unsigned long ants = 3000000000;
// or long long ants = 3000000000;
//Note: Don’t count on int being large enough to hold 3,000,000,000.Also if your
//system supports universal list-initialization, you could use it:
short rbis = {80}; // = is optional
unsigned int q {42110}; // could use = {42110}
long long ants {3000000000};
03. What safeguards does C++ provide to keep you from exceeding the limits of an integer type?
C++ provides no automatic safeguards to keep you from exceeding integer limits; you can use theclimits header file to determine what the limits are.
04. What is the distinction between 33L and 33?
The constant 33L is type long, whereas the constant 33 is type int.
05. Consider the two C++ statements that follow: Are they equivalent?
The two statements are not really equivalent, although they have the same effect on some systems. Most importantly, the first statement assigns the letterA
to grade only on a system using the ASCII code, while the second statement
also works for other codes. Second, 65 is a type int constant, whereas 'A'
is a type char constant.
06. How could you use C++ to find out which character the code 88 represents? Come up with at least two ways.
Here are four ways:
07. Assigning a long value to a float can result in a rounding error.
What about assigning long to double ? long long to double ?
The answer depends on how large the two types are. If long is 4 bytes,
there is no loss. That’s because the largest long value would be about
2 billion, which is 10 digits. Because double provides at least 13 significant
figures, no rounding would be needed. The long long type, on the other hand,
can reach 19 digits, which exceeds the 13 significant figures guaranteed for double .
08. Evaluate the following expressions as C++ would:
09. Suppose x1 and x2 are two type double variables that you want to
add as integers and assign to an integer variable. Construct a C++ statement
for doing so. What if you want to add them as type double and then convert to int ?
Either of the following would work for the first task:
To add them as type double and then convert, you could do either of the following:
10. What is the variable type for each of the following declarations?
Chapter 4
01. How would you declare each of the following?
02. Do Chapter Review Question 1 and use the array template class instead of built-in arrays.
03. Declare an array of five ints and initialize it to the first five odd positive integers
04. Write a statement that assigns the sum of the first and last elements of the array in Question 3 to the variable even.
05. Write a statement that displays the value of the second element in the float array ideas.
06. Declare an array of char and initialize it to the string "cheeseburger".
07. Declare a string object and initialize it to the string "Waldorf Salad".
08. Devise a structure declaration that describes a fish. The structure should include the kind, the weight in whole ounces, and the length in fractional inches.
09. Declare a variable of the type defined in Question 8 and initialize it.
10. Use enum to define a type called Response with the possible values Yes,
No, and Maybe.
Yes should be 1, No
should be 0, and Maybe should be 2.
11. Suppose ted is a double variable. Declare a pointer that points to ted and use the pointer to display ted’s value.
12. Suppose treacle is an array of 10 floats. Declare a pointer that points to the first element of treacle and use the pointer to display the first and last elements of the array.
13. Write a code fragment that asks the user to enter a positive integer and
then creates a dynamic array of that many ints.
Do this by using new, then again using a vector object.
14. Is the following valid code? If so, what does it print?
//Yes //Start of memory of this Literal Yes, it is valid. The expression "Home of the jolly bytes" is a string constant; hence it evaluates as the address of the beginning of the string. The cout object interprets the address of a char as an invitation to print a string, but the type cast (int *) converts the address to type pointer-to-int, which is then printed as an address. In short, the statement prints the address of the string, assuming the int type is wide enough to hold an address.
15. Write a code fragment that dynamically allocates a structure of the type
described in Question 8 and then reads a value for the kind member of the structure.
16. Listing 4.6 (numstr.cpp) illustrates a problem created by following numeric input with line-oriented string input. How would replacing:
cin >> address will read from user only to the space. Data after space will be in the queue;
Using cin >> address causes a program to skip over whitespace until it finds non-whitespace.
It then reads characters until it encounters whitespace again. Thus, it
will skip over the newline following the numeric input, avoiding that problem. On
the other hand, it will read just a single word, not an entire line.
17. Declare a vector object of 10 string objects and an array object of 10 string objects. Show the necessary header files and don’t use using. Do use a const for the number of strings.
Chapter 5
01. What’s the difference between an entry-condition loop and an exit-condition loop? Which kind is each of the C++ loops?
// entry-condition loop - check condition before entering the loop// exit-condition loop - check condition at the end of loop, making at least 1 loop
An entry-condition loop evaluates a test expression before entering the body of the loop. If the condition is initially false, the loop never executes its body. An exitcondition loop evaluates a test expression after processing the body of the loop. Thus, the loop body is executed once, even if the test expression is initially false. The for and while loops are entry-condition loops, and the do while loop is an exit-condition loop
02. What would the following code fragment print if it were part of a valid program?
It would print the following: Note thatcout << endl; is not part of the loop body (because there are no
braces).
03. What would the following code fragment print if it were part of a valid program?
It would print the following:04. What would the following code fragment print if it were part of a valid program?
It would print the following:05. What would the following code fragment print if it were part of a valid program?
It would print the following:
06. Write a for loop that prints the values 1 2 4 8 16 32 64 by increasing the value of
a counting variable by a factor of two in each cycle.
It’s simplest to use the *= operator:07. How do you make a loop body include more than one statement?
//add curly braces{} You enclose the statements within paired braces to form a single compound statement, or block.
08. Is the following statement valid? If not, why not? If so, what does it do? What about the following?
//1st is valid, but 1 will be assigned to x due to precedence and first value will do nothing//in 2nd 1 will be assigned to y, and 024 will do nothing, but confuse.
Yes, the first statement is valid. The expression 1, 024 consists of two expressions — 1 and 024 — joined by a comma operator. The value is the value of the right-hand expression. This is 024, which is octal for 20, so the declaration assigns the value 20 to x. The second statement is also valid. However, operator precedence causes it to be evaluated as follows: That is, the left expression sets y to 1, and the value of the entire expression, which isn’t used, is
024 , or 20 .
09. How does cin >> ch differ from cin.get(ch) and ch=cin.get() in how it views
input?
// My answer
cin>>ch will omit spaces, cin.get(ch) will return bool true, false if EOF,
ch=cin.get() will assign int value and EOF if EOF // Answer in the book The
cin >> ch form skips over spaces, newlines, and tabs when it encounters them.
The other two forms read those characters
Chapter 6
01. Consider the following two code fragments for counting spaces and newlines What advantages, if any, does the second form have over the first?
// My answer Because version 1 checks every times both conditions, thus it's less efficient.Version 2 checks 2 condition only if first is not true.
// Answer in the book Both versions give the same answers, but the if else version is more efficient. Consider what happens, for example, when ch is a space. Version 1, after incrementing spaces, tests whether the character is a newline. This wastes time because the program has already established that ch is a space and hence could not be a newline. Version 2, in the same situation, skips the newline test.
02. In Listing 6.2, what is the effect of replacing ++ch with ch+1?
Listing 6.2 ifelse.cpp
// ifelse.cpp -- using the if else statement
#include <iostream>
int
main()
{
char ch;
std::cout << "Type, and I shall repeat.\n";
std::cin.get(ch);
while (ch != '.')
{
if (ch == '\n')
std::cout << ch; // done if newline
else
std::cout << ++ch; // done otherwise
std::cin.get(ch);
}
std::cout << "\nPlease excuse the slight confusion.\n";
return 0;
}
// My answer
The Listing 6.2 ifelse.cpp
// ifelse.cpp -- using the if else statement
#include <iostream>
int
main()
{
char ch;
std::cout << "Type, and I shall repeat.\n";
std::cin.get(ch);
while (ch != '.')
{
if (ch == '\n')
std::cout << ch; // done if newline
else
std::cout << ++ch; // done otherwise
std::cin.get(ch);
}
std::cout << "\nPlease excuse the slight confusion.\n";
return 0;
}
char is promoted to int , and display numbers
// Answer in the book
Both ++ch and ch + 1 have the same numerical value. But ++ch is type char and
prints as a character, while ch + 1 , because it adds a char to an int ,
is type int and prints as a number.
03. Carefully consider the following program: Suppose you provide the following input, pressing the Enter key at the end of each line: What is the output? (Recall that input is buffered.)
// My answer// Program print after every read character `$` and if in input is `$` , the while loop will end.
// `Hi!`
// `H$i$!$`
// `$Send $10 or $20 now!`
// `S$e$n$d$ $ct1 = 8, ct2 = 8` // `$` is added even newline, and `ct` is added with it, I didn't include that
ch = `$` instead of ch == `$` , the combined input and
output looks like this:
Each character is converted to the $ character before being printed the second
time. Also the value of the expression ch = $ is the code for the $ character, hence
nonzero, hence true ; so ct2 is incremented each time.
04. Construct logical expressions to represent the following conditions:
a. weight is greater than or equal to 115 but less than 125.
b. ch is q or Q.
c. x is even but is not 26.
d. x is even but is not a multiple of 26.
e. donation is in the range 1,000–2,000 or guest is 1.
f. ch is a lowercase letter or an uppercase letter. (Assume, as is true for ASCII,
that lowercase letters are coded sequentially and that uppercase letters are coded
sequentially but that there is a gap in the code between uppercase and lowercase.)
a. weight is greater than or equal to 115 but less than 125.
b. ch is q or Q.
c. x is even but is not 26.
d. x is even but is not a multiple of 26.
e. donation is in the range 1,000–2,000 or guest is 1.
f. ch is a lowercase letter or an uppercase letter. (Assume, as is true for ASCII,
that lowercase letters are coded sequentially and that uppercase letters are coded
sequentially but that there is a gap in the code between uppercase and lowercase.)
05. In English, the statement “I will not not speak” means the same as
“I will speak.” In C++, is !!x the same as x?
//My answer
No. Return from `!!x` is boolean/int, while `x` have defined type by programmer
// Answer in the book
Not necessarily. For example, if `x` is 10, then `!x` is 0 and `!!x` is 1.
However, if `x` is a `bool` variable, then `!!x` is `x` .
06. Construct a conditional expression that is equal to the absolute value of a variable. That is, if a variable x is positive, the value of the expression is just x, but if x is negative, the value of the expression is -x, which is positive.
07. Rewrite the following fragment using switch:
08. In Listing 6.10, what advantage would there be in using character labels,
such as a and c, instead of numbers for the menu choices and switch cases?
(Hint: Think about what happens if the user types q in either case and what
happens if the user types 5 in either case.)
Listing 6.10 switch.cpp
// switch.cpp -- using the switch statement
#include <iostream>
using namespace std;
void showmenu(); // function prototypes
void report();
void comfort();
int main()
{
showmenu();
int choice;
cin >> choice;
while (choice != 5)
{
switch (choice)
{
case 1:
cout << "\a\n";
break;
case 2:
report();
break;
case 3:
cout << "The boss was in all day.\n";
break;
case 4:
comfort();
break;
default:
cout << "That's not a choice.\n";
}
showmenu();
cin >> choice;
}
cout << "Bye!\n";
return 0;
}
void showmenu()
{
cout << "Please enter 1, 2, 3, 4, or 5:\n"
"1) alarm 2) report\n"
"3) alibi 4) comfort\n"
"5) quit\n";
}
void report()
{
cout << "It's been an excellent week for business.\n"
"Sales are up 120%. Expenses are down 35%.\n";
}
void comfort()
{
cout << "Your employees think you are the finest CEO\n"
"in the industry. The board of directors think\n"
"you are the finest CEO in the industry.\n";
}
// Character labels would be more resistant to invalid input (characters promoted to int instead numbers); Listing 6.10 switch.cpp
// switch.cpp -- using the switch statement
#include <iostream>
using namespace std;
void showmenu(); // function prototypes
void report();
void comfort();
int main()
{
showmenu();
int choice;
cin >> choice;
while (choice != 5)
{
switch (choice)
{
case 1:
cout << "\a\n";
break;
case 2:
report();
break;
case 3:
cout << "The boss was in all day.\n";
break;
case 4:
comfort();
break;
default:
cout << "That's not a choice.\n";
}
showmenu();
cin >> choice;
}
cout << "Bye!\n";
return 0;
}
void showmenu()
{
cout << "Please enter 1, 2, 3, 4, or 5:\n"
"1) alarm 2) report\n"
"3) alibi 4) comfort\n"
"5) quit\n";
}
void report()
{
cout << "It's been an excellent week for business.\n"
"Sales are up 120%. Expenses are down 35%.\n";
}
void comfort()
{
cout << "Your employees think you are the finest CEO\n"
"in the industry. The board of directors think\n"
"you are the finest CEO in the industry.\n";
}
// It would also not go into infinite loop due to buffered characters from user input
If you use integer labels and the user types a noninteger such as q, the program hangs because integer input can’t process a character. But if you use character labels and the user types an integer such as 5, character input will process 5 as a character. Then the default part of the switch can suggest entering another character.
09. Consider the following code fragment: Rewrite this code without using break or continue.
Chapter 7
01. What are the three steps in using a function?
The three steps are defining the function, providing a prototype, and calling the function.
02. Construct function prototypes that match the following descriptions:
- igor() takes no arguments and has no return value.
- tofu() takes an int argument and returns a float.
- mpg() takes two type double arguments and returns a double.
- summation() takes the name of a long array and an array size as values and returns a long value.
- doctor() takes a string argument (the string is not to be modified) and returns a double value.
- ofcourse() takes a boss structure as an argument and returns nothing.
- plot() takes a pointer to a map structure as an argument and returns a string.
03. Write a function that takes three arguments: the name of an int array, the array size, and an int value. Have the function set each element of the array to the int value.
04. Write a function that takes three arguments: a pointer to the first element of a range in an array, a pointer to the element following the end of a range in an array, and an int value. Have the function set each element of the array to the int value.
05. Write a function that takes a double array name and an array size as arguments and returns the largest value in that array. Note that this function shouldn’t alter the contents of the array.
// // My solution -> tested
// double fnTemp(const double name[], int size){
// double max = name[0];
// for(int i {}; i < size; ++i)
// if(name[i] > max)
// max = name[i];
// return max;
// }
double biggest (const double foot[], int size)
{
double max;
if (size < 1)
{
cout << "Invalid array size of " << size << endl;
cout << "Returning a value of 0\n";
return 0;
}
else // not necessary because return terminates program
{
max = foot[0];
for (int i = 1; i < size; i++)
if (foot[i] > max)
max = foot[i];
return max;
}
}
06. Why don’t you use the const qualifier for function arguments that are one of the fundamental types?
You use the const qualifier with pointers to protect the original pointed-to data from being altered. When a program passes a fundamental type such as an int or a double, it passes it by value so that the function works with a copy. Thus, the original data is already protected.07. What are the three forms a C-style string can take in a C++ program?
A string can be stored in achar array , it can be represented by a string constant in double quotation marks, and it can
be represented by a pointer pointing to the first character of a string.
08. Write a function that has this prototype: Have the function replace every occurrence of c1 in the string str with c2, and have the function return the number of replacements it makes.
09. What does the expression *"pizza" mean? What about "taco"[2]?
Because C++ interprets "pizza" as the address of its first element, applying the * operator yields the value of that
first element, which is the character p. Because C++ interprets "taco" as the address of its first element, it interprets
"taco"[2] as the value of the element two positions down the line that is, as the character c . In other words, the string
constant acts the same as an array name
10. C++ enables you to pass a structure by value, and it lets you pass the address of a structure. If glitz is a structure variable, how would you pass it by value? How would you pass its address? What are the trade-offs of the two approaches?
// My answer
By value: fun(glitz)
- it copies everything from glitz to local structure - less efficient
By address: fun(*glitz)
- operates on original data - more prone to data corruption
- less understandable, use indirect membership operator (->)
glitz . To pass its address, you use the address operator &glitz.
Passing by the value automatically protects the original data, but it takes time and memory.
Passing by address saves time and memory but doesn’t protect the original data unless you use the const modifier for the
function parameter. Also passing by value means you can use ordinary structure member notation, but passing a pointer
means you have to remember to use the indirect membership operator.
11. The function judge() has a type int return value. As an argument, it takes the
address of a function. The function whose address is passed, in turn, takes a pointer
to a const char as an argument and returns an int. Write the function prototype.
12. Suppose we have the following structure declaration: - Write a function that takes an applicant structure as an argument and displays its contents. - Write a function that takes the address of an applicant structure as an argument and displays the contents of the pointed-to structure
// My answerfnTemp(applicant)(
std::cout << applicant.name << " " << applicant.credit_ratings;
)
fnTemp(*applicant)(
std::cout << applicant->name << " " << applicant->credit_ratings;
)
ap is an applicant structure, then ap.credit_ratings is an array name and ap.credit_ratings[i]
is an array element.
void display(applicant ap)
{
cout << ap.name << endl;
for (int i = 0; i < 3; i++)
cout << ap.credit_ratings[i] << endl;
}
pa->credit_ratings is an array name and
pa->credit_ratings[i] is an array element.
13. Suppose the functions f1() and f2() have the following prototypes:
Declare p1 as a pointer that points to f1 and p2 as a pointer to f2 .
Declare ap as an array of five pointers of the same type as p1 ,
and declare pa as a pointer to an array of ten pointers of the same type as p2 .
Use typedef as an aid.
Chapter 8
01. What kinds of functions are good candidates for inline status?
// Short ones. // The ones, that are not repeatable Short, nonrecursive functions that can fit in one line of code are good candidates forinline status .
02. Suppose the song() function has this prototype:
a. How would you modify the prototype so that the default value for times is 1?
b. What changes would you make in the function definition?
c. Can you provide a default value of "O, My Papa" for name?
a.
b. None. Only prototypes contain the default value information.
c. Yes, provided that you retain the default value for times:
03. Write overloaded versions of iquote(), a function that displays its argument
enclosed in double quotation marks. Write three versions: one for an int argument,
one for a double argument, and one for a string argument.
You can use either the string "\"" or the character " to print a quotation mark.
The following functions show both methods:
04. The following is a structure template:
a. Write a function that has a reference to a box structure as its formal argument
and displays the value of each member.
b. Write a function that has a reference to a box structure as its formal argument
and sets the volume member to the product of the other three dimensions.
a. This function shouldn’t alter the structure members, so use the const qualifier:
b.
05. What changes would need be made to Listing 7.15 (arrobj) so that the functions fill()
and show() use reference parameters?
Note that show() should use const to protect the object from being modified.
Next, within main() , change the fill() call to this:
Note that (*pa)[i] gets changed to the simpler pa[i] .
Finally, the only change to show() is to the function header.
// arrobj.cpp -- functions with array objects (C++11)
#include <iostream>
#include <array>
#include <string>
// constant data
const int Seasons = 4;
const std::array<std::string, Seasons> Snames =
{"Spring", "Summer", "Fall", "Winter"};
// function to modify array object
void fill(std::array<double, Seasons> &pa);
// function that uses array object without modifying it
void show(const std::array<double, Seasons> &da);
int main()
{
std::array<double, Seasons> expenses;
fill(expenses);
show(expenses);
return 0;
}
void fill(std::array<double, Seasons> &pa)
{
using namespace std;
for (int i = 0; i < Seasons; i++)
{
cout << "Enter " << Snames[i] << " expenses: ";
cin >> pa[i];
}
}
void show(const std::array<double, Seasons> &da)
{
using namespace std;
double total = 0.0;
cout << "\nEXPENSES\n";
for (int i = 0; i < Seasons; i++)
{
cout << Snames[i] << ": $" << da[i] << endl;
total += da[i];
}
cout << "Total Expenses: $" << total << endl;
}
06. The following are some desired effects. Indicate whether each can be accomplished
with default arguments, function overloading, both, or neither. Provide
appropriate prototypes.
a. mass(density, volume) returns the mass of an object having a density of
density and a volume of volume , whereasmass(density) returns the mass
having a density ofdensity and a volume of 1.0 cubic meters. All quantities
are typedouble.
b. repeat(10, "I'm OK") displays the indicated string 10 times, and
repeat("But you're kind of stupid") displays the indicated string 5
times.
c. average(3, 6) returns the int average of two int arguments, and
average(3.0, 6.0) returns the double average of two double values.
d. mangle("I'm glad to meet you") returns the character I or a pointer to
the string "I'm mad to gleet you", depending on whether you assign the
return value to a char variable or to a char* variable.
// My answer
double mass(double density, double volume = 1);
void repeat(int num, const char * words[]);
void repeat(const char * words[], int num = 5);
int average(int numA, int numB);
double average(double numA, double numB);
???
// Answer in the book
// a. This can be done by using a default value for the second argument:
double mass(double d, double v = 1.0);
It can also be done by using function overloading:
double mass(double d, double v);
double mass(double d);
// b. You can’t use a default for the repeat value because you have to provide
// default values from right to left. You can use overloading:
void repeat(int times, const char * str);
void repeat(const char * str);
// c. You can use function overloading:
int average(int a, int b);
double average(double x, double y);
// d. You can’t do this because both versions would have the same signature.
07. Write a function template that returns the larger of its two arguments.
08. Given the template of Chapter Review Question 7 and the box structure of Chapter Review Question 4, provide a template specialization that takes two box arguments and returns the one with the larger volume.
09. What types are assigned to v1, v2, v3, v4, and v5 in the following code (assuming the code is part of a complete program)?
Chapter 9
01. What storage scheme would you use for the following situations?
a. homer is a formal argument (parameter) to a function.
b. The secret variable is to be shared by two files.
c. The topsecret variable is to be shared by the functions in one file but hidden
from other files.
d. beencalled keeps track of how many times the function containing it has
been called.
a. homer is automatically an automatic variable.
b. secret should be defined as an external variable in one file and declared using extern in the second file.
c. topsecret could be defined as a static variable with internal linkage by prefacing the external definition with the
keyword static. Or it could be defined in an unnamed namespace.
d. beencalled should be defined as a local static variable by prefacing a declaration in the function with the
keyword static.
02. Describe the differences between a using declaration and a using directive
//Declaration will only allow to use one declared thing from namespace.
//Directive will allow to use all things declared namespace.
A using declaration makes available a single name from a namespace, and it has the
scope corresponding to the declarative region in which the using declaration
occurs. A using directive makes available all the names in a namespace. When you
use a using directive, it is as if you have declared the names in the smallest declarative
region containing both the using declaration and the namespace itself.
03. Rewrite the following so that it doesn’t use using declarations or using directives:
04. Rewrite the following so that it uses using declarations instead of the using directive:
05. Suppose you want the average(3,6) function to return an int average of the two
int arguments when it is called in one file, and you want it to return a double
average of the two int arguments when it is called in a second file in the same program.
How could you set this up?
You could have separate static function definitions in each file. Or each file could
define the appropriate average() function in an unnamed namespace.
06. What will the following two-file program display?
// file1.cpp
#include <iostream>
using namespace std;
void other();
void another();
int x = 10;
int y;
int main()
{
cout << x << endl;
{
int x = 4;
cout << x << endl;
cout << y << endl;
}
other();
another();
return 0;
}
void other()
{
int y = 1;
cout << "Other: " << x << ", " << y << endl;
}
// file 2.cpp
#include <iostream>
using namespace std;
extern int x;
namespace
{
int y = -4;
}
void another()
{
cout << "another(): " << x << ", " << y << endl;
}
// file1.cpp
#include <iostream>
using namespace std;
void other();
void another();
int x = 10;
int y;
int main()
{
cout << x << endl;
{
int x = 4;
cout << x << endl;
cout << y << endl;
}
other();
another();
return 0;
}
void other()
{
int y = 1;
cout << "Other: " << x << ", " << y << endl;
}
// file 2.cpp
#include <iostream>
using namespace std;
extern int x;
namespace
{
int y = -4;
}
void another()
{
cout << "another(): " << x << ", " << y << endl;
}
07. What will the following program display?
#include <iostream>
using namespace std;
void other();
namespace n1
{
int x = 1;
}
namespace n2
{
int x = 2;
}
int main()
{
using namespace n1;
cout << x << endl;
{
int x = 4;
cout << x << ", " << n1::x << ", " << n2::x << endl;
}
using n2::x;
cout << x << endl;
other();
return 0;
}
void other()
{
using namespace n2;
cout << x << endl;
{
int x = 4;
cout << x << ", " << n1::x << ", " << n2::x << endl;
}
using n2::x;
cout << x << endl;
}
#include <iostream>
using namespace std;
void other();
namespace n1
{
int x = 1;
}
namespace n2
{
int x = 2;
}
int main()
{
using namespace n1;
cout << x << endl;
{
int x = 4;
cout << x << ", " << n1::x << ", " << n2::x << endl;
}
using n2::x;
cout << x << endl;
other();
return 0;
}
void other()
{
using namespace n2;
cout << x << endl;
{
int x = 4;
cout << x << ", " << n1::x << ", " << n2::x << endl;
}
using n2::x;
cout << x << endl;
}
Chapter 10
01. What is a class?
Schema for creating object. A class is a definition of a user-defined type. A class declaration specifies how data is to be stored, and it specifies the methods (class member functions) that can be used to access and manipulate that data.02. How does a class accomplish abstraction, encapsulation, and data hiding?
by division of methods and variables bypublic and private
A class represents the operations you can perform on a class object with a public
interface of class methods; this is abstraction. The class can use private visibility (the
default) for data members, meaning that the data can be accessed only through the
member functions; this is data hiding. Details of the implementation, such as data
representation and method code, are hidden; this is encapsulation.
03. What is the relationship between an object and a class?
Class is used for creating object and defining its behaviour. We can use object on operate on it in accordance to the methods defined in class. A class defines a type, including how it can be used. An object is a variable or another data object, such as that produced by new, which is created and used according to the class definition. The relationship between a class and an object is the same as that between a standard type and a variable of that type04. In what way, aside from being functions, are class function members different from class data members?
Class functions are used with objects and part of the processed data can be encapsulated. If you create several objects of a given class, each object comes with storage for its own set of data. But all the objects use the one set of member functions. (Typically, methods are public and data members are private, but that’s a matter of policy, not of class requirements.)05. Define a class to represent a bank account. Data members should include the depositor’s name, the account number (use a string), and the balance. Member functions should allow the following: - Creating an object and initializing it. - Displaying the depositor’s name, account number, and balance - Depositing an amount of money given by an argument - Withdrawing an amount of money given by an argument Just show the class declaration, not the method implementations. (Programming Exercise 1 provides you with an opportunity to write the implementation.)
// #include <cstring>
// class definition
class BankAccount
{
private:
char name[40]; // or std::string name;
char acctnum[25]; // or std::string acctnum;
double balance;
public:
BankAccount(const char * client, const char * num, double bal = 0.0);
//or BankAccount(const std::string & client,
// const std::string & num, double bal = 0.0);
void show(void) const;
void deposit(double cash);
void withdraw(double cash);
};
06. When are class constructors called? When are class destructors called?
constructors are called when object is created and during initialization. destructors are called when object is deleted or on the end of the program. A class constructor is called when you create an object of that class or when you explicitly call the constructor. A class destructor is called when the object expires.07. Provide code for a constructor for the bank account class from Chapter Review Question 5.
These are two possible solutions (note that you must include cstring or string.h in order to usestrncpy() or else you must include string to use the string
class):
or
Keep in mind that default arguments go in the prototype, not in the function definition.
08. What is a default constructor? What is the advantage of having one?
It initializes class without any arguments. A default constructor either has no arguments or has defaults for all the arguments. Having a default constructor enables you to declare objects without initializing them, even if you’ve already defined an initializing constructor. It also allows you to declare arrays.09. Modify the Stock class definition (the version in stock20.h) so that it has member functions that return the values of the individual data members. Note: A member that returns the company name should not provide a weapon for altering the array. That is, it can’t simply return a string reference. It could return a const reference.
// stock30.h
#ifndef STOCK30_H_
#define STOCK30_H_
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_tot() { total_val = shares * share_val; }
public:
Stock(); // default constructor
Stock(const std::string & co, long n, double pr);
~Stock() {} // do-nothing destructor
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show() const;
const Stock & topval(const Stock & s) const;
int numshares() const { return shares; }
double shareval() const { return share_val; }
double totalval() const { return total_val; }
const string & co_name() const { return company; }
};
10. What are this and *this?
this - pointer to current object
*this - dereferention of object (object itself)
The this pointer is available to class methods. It points to the object used to
invoke the method. Thus, this is the address of the object, and *this represents the
object itself.
Chapter 11
01. Use a member function to overload the multiplication operator for the Stonewt
class; have the operator multiply the data members by a type double value. Note
that this will require carry over for the stone–pound representation. That is, twice 10
stone 8 pounds is 21 stone 2 pounds.
// My answer
// Answer in the book
Here’s a prototype for the class definition file and a function definition for the
methods file:
02. What are the differences between a friend function and a member function?
// My answer Friend functions have access to private data of a class (ivoked object). // Answer in the book A member function is part of a class definition and is invoked by a particular object.The member function can access members of the invoking object implicitly, without using the membership operator. A friend function is not part of a class, so it’s called as a straight function call. It can’t access class members implicitly, so it must use the membership operator applied to an object passed as an argument. Compare, for instance, the answer to Review Question 1 with the answer to Review Question 4.03. Does a nonmember function have to be a friend to access a class’s members?
// My answer For the direct access to the private members - Yes For the direct access to the public members - No For indirect access - via public methods - No // Answer in the book It must be a friend to access private members, but it doesn’t have to be a friend to access public members.04. Use a friend function to overload the multiplication operator for the Stonewt class; have the operator multiply the double value by the Stone value.
// My answerclass Stonewt{
private:
enum{Pds_to_stn = 14};
int stone;
double fracPound;
double pound;
public:
// code ...
friend Stonewt operator*(double mt, Stonewt &dm){
Stone tmp;
tmp.stone = dm.stone;
tmp.fracPound = dm.fracPound;
tmp.pound = dm.pound;
tmp.stone *= (int)mt;
tmp.fracPound += (int)mt % Pds_to_stn + mt - int(mt);
tmp.pound *= mt;
tmp.stone += (int)dm.pound % Pds_to_stn;
tmp.pound -= int(dm.pound);
return tmp;
}
}
05. Which operators cannot be overloaded?
The following five operators cannot be overloaded:
06. What restriction applies to overloading the following operators? =, (), [], and ->
These operations cannot overload basic functions they currently perform,
thus they need to be defined by using a member function.
07. Define a conversion function for the Vector class that converts a Vector object to a type double value that represents the vector’s magnitude.
// My answer - it should be by simple context.. againclass Vector{
private:
double x;
double y;
public:
// code ...
// option 1
double conv(Vector vc) const{
return sqrt(vc.x * vc.x + vc.y * vc.y);
}
// option 2
operator double(){
return sqrt(vc.x * vc.x + vc.y * vc.y);
}
}
magval() method than to
define this conversion function.
Chapter 12
01. Suppose a String class has the following private members: a. What’s wrong with this default constructor? b. What’s wrong with this constructor? c. What’s wrong with this constructor?
a. Constructor won't initialize data for proper use of object b. It is so called `shallow copy` for str. It will copy only pointer `s` to string, thus two objects will point into the same string c. `s` is `const` and is put into function // Answer in the book a. The syntax is fine, but this constructor leaves the `str` pointer uninitialized. The constructor should either set the pointer to NULL or use `new []` to initialize the pointer. b. This constructor does not create a new string; it merely copies the address of the old string. It should use `new []` and `strcpy()`. c. It copies the string without allocating the space to store it. It should use new `char[len + 1]` to allocate the proper amount of memory.
02. Name three problems that may arise if you define a class in which a pointer member
is initialized by using new. Indicate how they can be remedied.
// Answer in the book
First, when an object of that type expires, the data pointed to by the object’s member
pointer remains in memory, using space and remaining inaccessible because the
pointer has been lost. That can be fixed by having the class destructor delete memory
allocated by `new` in the constructor functions.
Second, after the destructor deletes such memory, it might end up trying to delete it twice if a program initializes
one such object to another.That’s because the default initialization of one
object to another copies pointer values but does not copy the pointed-to data, and
this produces two pointers to the same data.The solution is to define a class copy
constructor that causes initialization to copy the pointed-to data.
Third, assigning one object to another can produce the same situation of two pointers pointing to
the same data. The solution is to overload the assignment operator so that it copies
the data, not the pointers.
03. What class methods does the compiler generate automatically if you don’t provide them explicitly? Describe how these implicitly generated functions behave.
// Answer in the book - A default constructor if you define no constructors - A copy constructor if you don’t define one - An assignment operator if you don’t define one - A default destructor if you don’t define one - An address operator if you don’t define one The default constructor does nothing, but it allows you to declare arrays and uninitialized objects. The default copy constructor and the default assignment operator use memberwise assignment.The default destructor does nothing.The implicit address operator returns the address of the invoking object (that is, the value of the `this` pointer).
04. Identify and correct the errors in the following class declaration:
class nifty
{
// data
char personality[];
int talents;
// methods
nifty();
nifty(char *s);
ostream &operator<<(ostream &os, nifty &n);
}
nifty : nifty()
{
personality = NULL;
talents = 0;
}
nifty : nifty(char *s)
{
personality = new char[strlen(s)];
personality = s;
talents = 0;
}
ostream &nifty : operator<<(ostream & os, nifty & n)
{
os << n;
}
class nifty
{
// data
char personality[];
int talents;
// methods
nifty();
nifty(char *s);
ostream &operator<<(ostream &os, nifty &n);
}
nifty : nifty()
{
personality = NULL;
talents = 0;
}
nifty : nifty(char *s)
{
personality = new char[strlen(s)];
personality = s;
talents = 0;
}
ostream &nifty : operator<<(ostream & os, nifty & n)
{
os << n;
}
class nifty
{
// data
char personality[];
int talents;
// methods
nifty();
nifty(char *s);
ostream &operator<<(ostream &os, nifty &n);
// Lack of destructor, when new is used
~nifty();
// Lack of assignment operator - shallow copy error
nifty &operator=(nifty n);
}
nifty : nifty()
{
personality = NULL;
talents = 0;
}
nifty : nifty(char *s)
{
personality = new char[strlen(s)];
// personality = s; // pointer assigned - shallow copy
strcpy(personality, s);
talents = 0;
}
ostream &nifty : operator<<(ostream & os, nifty & n)
{
os << n;
}
~nifty : nifty(){
delete personality;
}
nifty &operator=(nifty n){
if(personality != NULL)
delete personality;
personality = new char[strlen(n.personality)];
strcpy(personality, n.personality);
talents = n.talents;
}
#include <iostream>
#include <cstring>
using namespace std;
class nifty
{
private: // optional
char personality[40]; // provide array size
int talents;
public: // needed
// methods
nifty();
nifty(const char *s);
friend ostream &operator<<(ostream &os, const nifty &n);
}; // note closing semicolon
nifty::nifty()
{
personality[0] = '\0';
talents = 0;
}
nifty::nifty(const char *s)
{
strcpy(personality, s);
talents = 0;
}
ostream &operator<<(ostream &os, const nifty &n)
{
os << n.personality << '\n';
os << n.talent << '\n';
return os;
}
05. Consider the following class declaration:
class Golfer
{
private:
char *fullname; // points to string containing golfer's name
int games; // holds number of golf games played
int *scores; // points to first element of array of golf scores
public:
Golfer();
Golfer(const char *name, int g = 0);
// creates empty dynamic array of g elements if g > 0
Golfer(const Golfer &g);
~Golfer();
};
a. What class methods would be invoked by each of the following statements ?
b. Clearly, the class requires several more methods to make it useful. What additional
method does it require to protect against data corruption?
a.
class Golfer
{
private:
char *fullname; // points to string containing golfer's name
int games; // holds number of golf games played
int *scores; // points to first element of array of golf scores
public:
Golfer();
Golfer(const char *name, int g = 0);
// creates empty dynamic array of g elements if g > 0
Golfer(const Golfer &g);
~Golfer();
};
Golfer nancy; // #1 Golfer()
Golfer lulu(“Little Lulu”); // #2 Golfer(const char *name, int g = 0);
Golfer roy(“Roy Hobbs”, 12); // #3 Golfer(const char *name, int g = 0);
Golfer *par = new Golfer; // #4 Golfer operator=(Golfer *n);
Golfer next = lulu; // #5 Golfer operator=(Golfer n); // wrong
Golfer hazzard = “Weed Thwacker”;// #6 Golfer operator=(String n); // wrong
*par = nancy; // #7 Golfer *operator=(Golfer n);
nancy = “Nancy Putter”; // #8 Golfer operator=(String n); // wrong
Golfer nancy; // default constructor
Golfer lulu("Little Lulu"); // Golfer(const char * name, int g)
Golfer roy("Roy Hobbs", 12); // Golfer(const char * name, int g)
Golfer * par = new Golfer; // default constructor
Golfer next = lulu; // Golfer(const Golfer &g)
Golfer hazard = "Weed Thwacker"; // Golfer(const char * name, int g)
*par = nancy; // default assignment operator
nancy = "Nancy Putter";// Golfer(const char * name, int g), then
// the default assignment operator
Chapter 13
01. What does a derived class inherit from a base class?
All public and protected methods and variables. // Answer in the book The public members of the base class become public members of the derived class. The protected members of the base class become protected members of the derived class.The private members of the base class are inherited but cannot be accessed directly. The answer to Review Question 2 provides the exceptions to these general rules.02. What doesn’t a derived class inherit from a base class?
The constructor methods are not inherited, the destructor is not inherited, the assignment operator is not inherited, and friends are not inherited.
03. Suppose the return type for the baseDMA::operator=() function were defined as
void instead of baseDMA &.
What effect, if any, would that have? What if the return
type were baseDMA instead of baseDMA &?
`void` - returns nothing instead of reference to `baseDMA`, that is you would not be able to return `baseDMA` object and its data via `=` so the chain assignment wont work, only single assignment
Returning object, not reference to it, makes execution slower due to necessity of copying everything to return it, instead of pointing to memory with already created object.
// Answer in the book
If the return type were void, you would still be able to use single assignment but
not chain assignment:
If the method returned an object instead of a reference, the method execution
would be slowed a bit because the return statement would involve copying the
object.
04. In what order are class constructors and class destructors called when a derived class object is created and deleted?
In reverse order to invoking constructors. In case of constructor with inheritance - it would be base class invoked via member initializator list `:`, constructed in order from left to right (in case of many classes). // Answer in the book Constructors are called in the order of derivation, with the most ancestral constructor called first. Destructors are called in the opposite order.05. If a derived class doesn’t add any data members to the base class, does the derived class require constructors?
Yes, and it need to invoke base class constructor. // Answer in the book Yes, every class requires its own constructors. If the derived class adds no new members, the constructor can have an empty body, but it must exist.06. Suppose a base class and a derived class both define a method with the same name and a derived-class object invokes the method. What method is called?
Method in derived class. // Answer in the book Only the derived-class method is called. It supersedes the base-class definition.A base-class method is called only if the derived class does not redefine the method or if you use the scope-resolution operator. However, you really should declare as virtual any functions that will be redefined07. When should a derived class define an assignment operator?
When it need to perform deep copy - that is, if it have dynamically allocated data. // Answer in the book The derived class should define an assignment operator if the derived-class constructors use the `new` or `new []` operator to initialize pointers that are members of that class. More generally, the derived class should define an assignment operator if the default assignment is incorrect for derived-class members.08. Can you assign the address of an object of a derived class to a pointer to the base class? Can you assign the address of an object of a base class to a pointer to the derived class?
Yes to both. Pointer of derived class to base class is called upcasting. Pointer of base class to derived class is called downcasting. // Answer in the book Yes, you can assign the address of an object of a derived class to a pointer to the base class. You can assign the address of a base-class object to a pointer to a derived class (downcasting) only by making an explicit type cast, and it is not necessarily safe to use such a pointer.09. Can you assign an object of a derived class to an object of the base class? Can you assign an object of a base class to an object of the derived class?
If you will make methods that will handle this - yes. // Answer in the book Yes, you can assign an object of a derived class to an object of the base class. Any data members that are new to the derived type are not passed to the base type, however. The program uses the base-class assignment operator. Assignment in the opposite direction (base to derived) is possible only if the derived class defines a `conversion operator`, which is a constructor that has a reference to the base type as its sole argument, or else defines an assignment operator with a base-class parameter.10. Suppose you define a function that takes a reference to a base-class object as an argument. Why can this function also use a derived-class object as an argument?
Because it is inherited. Derived class object holds base class object. // Answer in the book It can do so because C++ allows a reference to a base type to refer to any type derived from that base.11. Suppose you define a function that takes a base-class object as an argument (that is, the function passes a base-class object by value). Why can this function also use a derived-class object as an argument?
Because it is inherited. Derived class object holds base class object. // Answer in the book Passing an object by value invokes the copy constructor. Because the formal argument is a base-class object, the base-class copy constructor is invoked.The copy constructor has as its argument a reference to the base class, and this reference can refer to the derived object passed as an argument.The net result is that a new baseclass object whose members correspond to the base class portion of the derived object is produced12. Why is it usually better to pass objects by reference than by value?
Because passing by value makes copy of an object, when reference is the address of the original object. // Answer in the book Passing an object by reference instead of by value enables the function to avail itself of virtual functions. Also passing an object by reference instead of by value may use less memory and time, particularly for large objects. The main advantage of passing by value is that it protects the original data, but you can accomplish the same end by passing the reference as a `const` type.
13. Suppose Corporation is a base class and PublicCorporation is a derived class. Also
suppose that each class defines a head() member function, that ph is a pointer to
the Corporation type, and that ph is assigned the address of a PublicCorporation
object. How is ph->head() interpreted if the base class defines head() as a
a. Regular nonvirtual method
b. Virtual method
- via regular method - the `PublicCorporation->head()` will be invoked
- via virtual method - the `Corporation->head()` will be invoked
// Answer in the book
If `head()` is a regular method, then `ph->head()` invokes `Corporation::head()`. If
`head()` is a virtual function, then `ph->head()` invokes
`PublicCorporation::head()`.
14. What’s wrong, if anything, with the following code?
class Kitchen
{
private:
double kit_sq_ft;
public:
Kitchen() { kit_sq_ft = 0.0; }
virtual double area() const { return kit_sq_ft * kit_sq_ft; }
};
class House : public Kitchen
{
private:
double all_sq_ft;
public:
House() { all_sq_ft += kit_sq_ft; }
double area(const char *s) const
{
cout << s;
return all_sq_ft;
}
};
Why `House` inherits `Kitchen`, instead containing it (it is has-a model) or via private deriviation(chapter 14)?
The keyword `virtual` in derived class `area` constructor don't need to be used, because base class function is overridden in a derived class via declared function as virtual in the base class.
`Kitchen` and `House` constructors don't allow any input that assigns value to private values, which mean the `kit_sq_ft` and `all_sq_ft` will always be `0.0`.
// Answer in the book
First, the situation does not fit the is-a model, so public inheritance is not appropriate.
Second, the definition of `area()` in `House` hides the `Kitchen` version of `area()`
because the two methods have different signatures.
class Kitchen
{
private:
double kit_sq_ft;
public:
Kitchen() { kit_sq_ft = 0.0; }
virtual double area() const { return kit_sq_ft * kit_sq_ft; }
};
class House : public Kitchen
{
private:
double all_sq_ft;
public:
House() { all_sq_ft += kit_sq_ft; }
double area(const char *s) const
{
cout << s;
return all_sq_ft;
}
};
Chapter 14
01. For each of the following sets of classes, indicate whether public or private derivation is more appropriate for Column B: |Lp|A|B| |---|---|---| |1|class Bear|class PolarBear| |2|class Kitchen|class Home| |3|class Person|class Programmer| |4|class Person|class HorseAndJockey| |5|class Person, class Automobile|class Driver|
// Answer in the book 1. Public; a polar bear is a kind of bear 2. Private; a home has a kitchen 3. Public; a programmer is a kind of person 4. Private; a horse and jockey team contains a person 5. Person public because a driver is a person; Automobile private because a driver has an automobile
02. Suppose you have the following definitions:
class Frabjous
{
private:
char fab[20];
public:
Frabjous(const char *s = "C++") : fab(s) {}
virtual void tell() { cout << fab; }
};
class Gloam
{
private:
int glip;
Frabjous fb;
public:
Gloam(int g = 0, const char *s = "C++");
Gloam(int g, const Frabjous &f);
void tell();
};
Given that the Gloam version of tell() should display the values of glip and fb, provide definitions for the three Gloam methods.
// Answer in the book
class Frabjous
{
private:
char fab[20];
public:
Frabjous(const char *s = "C++") : fab(s) {}
virtual void tell() { cout << fab; }
};
class Gloam
{
private:
int glip;
Frabjous fb;
public:
Gloam(int g = 0, const char *s = "C++");
Gloam(int g, const Frabjous &f);
void tell();
};
03. Suppose you have the following definitions:
class Frabjous
{
private:
char fab[20];
public:
Frabjous(const char *s = "C++") : fab(s) {}
virtual void tell() { cout << fab; }
};
class Gloam : private Frabjous
{
private:
int glip;
public:
Gloam(int g = 0, const char *s = "C++");
Gloam(int g, const Frabjous &f);
void tell();
};
Given that the Gloam version of tell() should display the values of glip and fab,
provide definitions for the three Gloam methods.
class Frabjous
{
private:
char fab[20];
public:
Frabjous(const char *s = "C++") : fab(s) {}
virtual void tell() { cout << fab; }
};
class Gloam : private Frabjous
{
private:
int glip;
public:
Gloam(int g = 0, const char *s = "C++");
Gloam(int g, const Frabjous &f);
void tell();
};
// Gloam::Gloam(int g, const char *s) // wrong
// {
// glip = g;
// this(s); // Error: this is a pointer, not a function - this keyword is a pointer to the current object, and it cannot be used to call constructor
// }
// Gloam::Gloam(int g, const Frabjous &f) // wrong
// {
// glip = g;
// this(f); // Error: this is a pointer, not a function
// }
Gloam::Gloam(int g, const char * s)
: glip(g), Frabjous(s) { }
Gloam::Gloam(int g, const Frabjous & fr)
: glip(g), Frabjous(fr) { }
void Gloam::tell()
{
cout << glip;
Frabjous::tell();
}
04. Suppose you have the following definition, based on the Stack template of Listing
14.13 (stacktp.h) and the Worker class of Listing 14.10 (workermi.h):
Write out the class declaration that will be generated. Just do the class declaration,
not the non-inline class methods.
template <class Worker *>
class Stack
{
private:
enum
{
MAX = 10
}; // constant specific to class
Worker * items[MAX]; // holds stack items
int top; // index for top stack item
public:
Stack();
bool isempty();
bool isfull();
bool push(const Worker &item); // add item to stack
bool pop(Worker &item); // pop top into item
};
class Stack<Worker *>
{
private:
enum {MAX = 10}; // constant specific to class
Worker * items[MAX]; // holds stack items
int top; // index for top stack item
public:
Stack();
Boolean isempty();
Boolean isfull();
Boolean push(const Worker * & item); // add item to stack
Boolean pop(Worker * & item); // pop top into item
};
05. Use the template definitions in this chapter to define the following:
- An array of string objects
- A stack of arrays of double
- An array of stacks of pointers to Worker objects
How many template class definitions are produced in Listing 14.18 (twod.cpp)?
In `twop.cpp` 4 template class definitions are produced
// Answer in the book
ArrayTP<string> sa;
StackTP< ArrayTP<double> > stck_arr_db;
ArrayTP< StackTP<Worker *> > arr_stk_wpr;
06. Describe the differences between virtual and nonvirtual base classes.
In case of upcasting, the base class methods for nonvirtual base class will not be invoked, which can result in errors // Answer in the book If two lines of inheritance for a class share a common ancestor, the class winds up having two copies of the ancestor’s members. Making the ancestor class a virtual base class to its immediate descendants solves that problem.Chapter 15
01. What’s wrong with the following attempts at establishing friends? a. b. c.
// Answer in the book a.The friend declaration should be as follows : b.This needs a forward declaration so that the compiler can interpret void snip(muff &) : c. First, the cuff class declaration should precede the muff class so that the compiler can understand the term cuff::snip(). Second, the compiler needs a forward declaration of muff so that it can understand snip(muff &) :02. You’ve seen how to create mutual class friends. Can you create a more restricted form of friendship in which only some members of Class B are friends to Class A and some members of A are friends to B? Explain.
With forward declaration: // Answer in the book No. For Class A to have a friend that’s a member function of Class B, the B declaration must precede the A declaration. A forward declaration is not enough because it would tell A that B is a class, but it wouldn’t reveal the names of the class members. Similarly, if B has a friend that’s a member function of A, the complete A declaration must precede the B declaration.These two requirements are mutually exclusive.03. What problems might the following nested class declaration have?
The public interface of nested Sauce class will only be visible (will have a scope of) Ribs class. // Answer in the book The only access to a class is through its public interface, which means the only thing you can do with a Sauce object is call the constructor to create one. The other members (soy and sugar) are private by default.
04. How does throw differ from return?
`throw()` will get directly into main - it is faster
`throw(fun)` can jump into desired function
// Answer in the book
Suppose the function f1() calls the function f2(). A return statement in f2()
causes program execution to resume at the next statement following the f2() function
call in function f1(). A throw statement causes the program to back up
through the current sequence of function calls until it finds a try block that
directly or indirectly contains the call to f2(). This might be in f1() or in a function
that called f1(), and so on. Once there, execution goes to the next matching
catch block, not to the first statement after the function call.
05. Suppose you have a hierarchy of exception classes that are derived from a base
exception class. In what order should you place catch blocks?
// Answer in the book
You should arrange the catch blocks in order, from most derived class to least
derived.
06. Consider the Grand, Superb, and Magnificent classes defined in this chapter. Suppose
pg is a type Grand * pointer that is assigned the address of an object of one of
these three classes and that ps is a type Superb * pointer.What is the difference in
how the following two code samples behave?
sample1 - if with dynamic cast - will assign any class as long as it is safe
sample2 - if with typeid - will only check if pg is the exact pointer of Superb class
// Answer in the book
For Sample #1, the if condition is true if pg points to a Superb object or to an
object of any class descended from Superb. In particular, it is also true if pg points
to a Magnificent object. In Sample #2, the if condition is true only for a Superb
object, not for objects derived from Superb.
07. How is the static_cast operator different from the dynamic_cast operator?
static_cast is only valid when compiler can convert type name into the same type expression has,
while dynamic_cast can assigning into expression is safe (upcasting)
// Answer in the book
The dynamic_cast operator only allows upcasting in a class hierarchy, whereas a
static_cast operator allows both upcasting and downcasting.The static_cast
operator also allows conversions from enumeration types to integer types, and vice
versa, and between various numeric types.
Chapter 16
01. Consider the following class declaration:
class RQ1
{
private:
char *st; // points to C-style string
public:
RQ1()
{
st = new char[1];
strcpy(st, "");
}
RQ1(const char *s)
{
st = new char[strlen(s) + 1];
strcpy(st, s);
}
RQ1(const RQ1 &rq)
{
st = new char[strlen(rq.st) + 1];
strcpy(st, rq.st);
}
~RQ1(){delete[] st};
RQ &operator=(const RQ &rq);
// more stuff
};
Convert this to a declaration that uses a string object instead.
What methods no longer need explicit definitions?
class RQ1
{
private:
char *st; // points to C-style string
public:
RQ1()
{
st = new char[1];
strcpy(st, "");
}
RQ1(const char *s)
{
st = new char[strlen(s) + 1];
strcpy(st, s);
}
RQ1(const RQ1 &rq)
{
st = new char[strlen(rq.st) + 1];
strcpy(st, rq.st);
}
~RQ1(){delete[] st};
RQ &operator=(const RQ &rq);
// more stuff
};
class RQ1
{
private:
std::string st;
public:
RQ1()
{
st = "";
}
RQ1(const char *s)
{
strcpy(st, s);
}
~RQ1(){};
RQ &operator=(const RQ &rq);
// more stuff
};
#include <string>
using namespace std;
class RQ1
{
private:
string st; // a string object
public:
RQ1() : st("") {}
RQ1(const char *s) : st(s) {}
~RQ1(){};
// more stuff
};
string object provides its own memory management.
02. Name at least two advantages string objects have over C-style strings in terms
of ease-of-use.
- string obj is an object, thus use destructor - for c-style you need to remember yourself to deallocate data
- string obj can be used with STL
// Answer in the book
You can assign one string object to another. A string object provides its own
memory management so that you normally don’t have to worry about a string
exceeding the capacity of its holder
03. Write a function that takes a reference to a string object as an argument and that
converts the string object to all uppercase.
// Answer in the book
04. Which of the following are not examples of correct usage (conceptually or syntactically)
of auto_ptr? (Assume that the needed header files have been included.)
`auto_ptr05. If you could make the mechanical equivalent of a stack that held golf clubs instead of numbers, why would it (conceptually) be a bad golf bag?
Because you will need to get/open all golf before correct one. // Answer in the book The LIFO aspect of a stack means you might have to remove a lot of clubs before reaching the one you need
06. Why would a set container be a poor choice for storing a hole-by-hole record of
your golf scores?
Because it can store only unique values.
// Answer in the book
The set will store just one copy of each value, so, say, five scores of 5 would be
stored as a single 5.
07. Because a pointer is an iterator, why didn’t the STL designers simply use pointers instead of iterators?
// Answer in the book Using iterators allows you to use objects with a pointer-like interface to move through data that is organized in some fashion other than an array (for example, data in a doubly linked list).08. Why didn’t the STL designers simply define a base iterator class, use inheritance to derive classes for the other iterator types, and express the algorithms in terms of those iterator classes?
// Answer in the book The STL approach allows STL functions to be used with ordinary pointers to ordinary arrays as well as with iterators to STL container classes, thus increasing generality.
09. Give at least three examples of convenience advantages that a vector object has
over an ordinary array.
- Dynamic and simple data allocation - .pushback(data)
- Use of STL: .size(), .sort()
- It uses destructor
// Answer in the book
You can assign one vector object to another. A vector manages its own memory,
so you can insert items into a vector and have it resize itself automatically. By using
the `at()` method, you can get automatic bounds checking.
10. If Listing 16.9 were implemented with list instead of vector, what parts of the
program would become invalid? Could the invalid part be fixed easily? If so, how?
// vect3.cpp -- using STL functions
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
struct Review
{
std::string title;
int rating;
};
bool operator<(const Review &r1, const Review &r2);
bool worseThan(const Review &r1, const Review &r2);
bool FillReview(Review &rr);
void ShowReview(const Review &rr);
int main()
{
using namespace std;
vector<Review> books;
Review temp;
while (FillReview(temp))
books.push_back(temp);
if (books.size() > 0)
{
cout << "Thank you. You entered the following "
<< books.size() << " ratings:\n"
<< "Rating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
sort(books.begin(), books.end());
cout << "Sorted by title:\nRating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
sort(books.begin(), books.end(), worseThan);
cout << "Sorted by rating:\nRating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
random_shuffle(books.begin(), books.end());
cout << "After shuffling:\nRating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
}
else
cout << "No entries. ";
cout << "Bye.\n";
return 0;
}
bool operator<(const Review &r1, const Review &r2)
{
if (r1.title < r2.title)
return true;
else if (r1.title == r2.title && r1.rating < r2.rating)
return true;
else
return false;
}
bool worseThan(const Review &r1, const Review &r2)
{
if (r1.rating < r2.rating)
return true;
else
return false;
}
bool FillReview(Review &rr)
{
std::cout << "Enter book title (quit to quit): ";
std::getline(std::cin, rr.title);
if (rr.title == "quit")
return false;
std::cout << "Enter book rating: ";
std::cin >> rr.rating;
if (!std::cin)
return false;
// get rid of rest of input line
while (std::cin.get() != '\n')
continue;
return true;
}
void ShowReview(const Review &rr)
{
std::cout << rr.rating << "\t" << rr.title << std::endl;
}
Declaration
// Answer in the book
The two `sort()` functions and the `random_shuffle()` function require a random
access iterator, whereas a list object just has a bidirectional iterator.You can use
the list template class `sort()` member functions (see Appendix G,“The STL
Methods and Functions”) instead of the general-purpose functions to do the sorting,
but there is no member function equivalent to `random_shuffle()`. However,
you could copy the list to a `vector`, shuffle the vector, and copy the results back to
the list.
// vect3.cpp -- using STL functions
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
struct Review
{
std::string title;
int rating;
};
bool operator<(const Review &r1, const Review &r2);
bool worseThan(const Review &r1, const Review &r2);
bool FillReview(Review &rr);
void ShowReview(const Review &rr);
int main()
{
using namespace std;
vector<Review> books;
Review temp;
while (FillReview(temp))
books.push_back(temp);
if (books.size() > 0)
{
cout << "Thank you. You entered the following "
<< books.size() << " ratings:\n"
<< "Rating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
sort(books.begin(), books.end());
cout << "Sorted by title:\nRating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
sort(books.begin(), books.end(), worseThan);
cout << "Sorted by rating:\nRating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
random_shuffle(books.begin(), books.end());
cout << "After shuffling:\nRating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
}
else
cout << "No entries. ";
cout << "Bye.\n";
return 0;
}
bool operator<(const Review &r1, const Review &r2)
{
if (r1.title < r2.title)
return true;
else if (r1.title == r2.title && r1.rating < r2.rating)
return true;
else
return false;
}
bool worseThan(const Review &r1, const Review &r2)
{
if (r1.rating < r2.rating)
return true;
else
return false;
}
bool FillReview(Review &rr)
{
std::cout << "Enter book title (quit to quit): ";
std::getline(std::cin, rr.title);
if (rr.title == "quit")
return false;
std::cout << "Enter book rating: ";
std::cin >> rr.rating;
if (!std::cin)
return false;
// get rid of rest of input line
while (std::cin.get() != '\n')
continue;
return true;
}
void ShowReview(const Review &rr)
{
std::cout << rr.rating << "\t" << rr.title << std::endl;
}
11. Consider the TooBig functor in Listing 16.15.
What does the following code do, and what values get assigned to bo?
used in functions/methods via operator overloading().
Returns bool 10>15;
// Answer in the AI
The given code snippet creates an instance of the `TooBig` functor with the template parameter `int`, and the cutoff value set to `10`. Then it calls the `operator()` function with the argument `15`.
The `TooBig` functor checks if the passed argument (`15`) is greater than the cutoff value (`10`). Since `15` is indeed greater than `10`, the function returns `true`. Therefore, the `boolean` variable `bo` is assigned the value `true`.
Chapter 17
01. What role does the iostream file play in C++ I/O?
It define classes that can create objects to control stream of data from and to selected source (default is keyboard).
// Answer in the book
The `iostream` file defines the classes, constants, and manipulators used to manage
input and output.These objects manage the streams and buffers used to handle I/O.
The file also creates standard objects (`cin`, `cout`, `cerr`, and `clog` and their widecharacter
equivalents) used to handle the standard input and output streams connected
to every program.
02. Why does typing a number such as 121 as input require a program to make a conversion?
It is a raw stream of data from keyboard, that to be displayed as human-readable text, need to be converted. // Answer in the book Keyboard entry generates a series of characters. Typing `121` generates three characters, each represented by a 1-byte binary code. If the value is to be stored as type int, these three characters have to be converted to a single binary representation of the value `121`.03. What’s the difference between the standard output and the standard error?
`standard output` describes stream of data from program to selected destination, while `standard error` describes fault in program that is send as stream of data to the standard output. // Answer in the book By default, both the standard output and the standard error send output to the standard output device, typically a monitor. If you have the operating system redirect output to a file, however, the standard output connects to the file instead of to the screen, but the standard error continues to be connected to the screen.
04. Why is cout able to display various C++ types without being provided explicit instructions for each type?
Due to large number of overloadings in insertion operators `<<` and extraction operators `>>`.
// Answer in the book
The `ostream` class defines a version of the `operator<<()` function for each basic
C++ type.The compiler interprets an expression like
as the following:
It can then match this method call to the function prototype that has the same
argument type.
05. What feature of the output method definitions allows you to concatenate output?
ios_base class file mode method `ios_base::app`, that append new data to the end of file. In case of reading the file, than changing the data, `.clear` method will clear `eof` flag and allow to further manipulate data. // Answer in the book You can concatenate output methods that return type `ostream &`. This causes the invoking of a method with an object to return that object. The returned object can then invoke the next method in a sequence.06. Write a program that requests an integer and then displays it in decimal, octal, and hexadecimal forms. Display each form on the same line, in fields that are 15 characters wide, and use the C++ number base prefixes.
#include <iostream>
int main(){
int data{};
std::cout << "\nEnter integer number: ";
std::cin >> data;
while (std::cin.get() != '\n') continue;
// Use + before positive numbers. - num base prefix
std::cout.setf(std::ios_base::showpos);
std::cout << "You have entered:\n";
std::cout << "In decimal:\t";
std::cout.width(15);
std::cout << data << std::endl;
std::cout << std::hex;
std::cout << "In hexadecimal:\t";
std::cout.width(15);
std::cout << data << std::endl;
std::cout << std::oct;
std::cout << "In octal:\t";
std::cout.width(15);
std::cout << data << std::endl;
std::cout << "\nAdios!";
return 0;
}
// rq17-6.cpp
#include <iostream>
#include <iomanip>
int main()
{
using namespace std;
cout << "Enter an integer: ";
int n;
cin >> n;
cout << setw(15) << "base ten" << setw(15)
<< "base sixteen" << setw(15) << "base eight"
<< "\n";
cout.setf(ios::showbase); // or cout << showbase;
cout << setw(15) << n << hex << setw(15) << n
<< oct << setw(15) << n << "\n";
return 0;
}
07. Write a program that requests the following information and that formats it as shown:
#include <iostream>
#include <string>
int main(){
std::string name;
float wage_hour{};
float work_hours{};
std::cout << "\nEnter your name: ";
std::getline(std::cin, name);
std::cout << "Enter your hourly wage_hours: ";
std::cin >> wage_hour;
while (std::cin.get() != '\n') continue;
std::cout << "Enter number of hours worked: ";
std::cin >> work_hours;
while (std::cin.get() != '\n') continue;
std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
std::cout << "First format:\n";
std::cout.precision(2);
std::cout << name << ": $ " << wage_hour;
std::cout.precision(1);
std::cout << ": " << work_hours << std::endl;
std::cout << "Second format:\n";
std::cout.precision(2);
std::cout << name << " : $" << wage_hour;
std::cout.precision(1);
std::cout << " :" << work_hours << std::endl;
std::cout << "\nAdios!";
return 0;
}
// rq17-7.cpp
#include <iostream>
#include <iomanip>
int main()
{
using namespace std;
char name[20];
float hourly;
float hours;
cout << "Enter your name: ";
cin.get(name, 20).get();
cout << "Enter your hourly wages: ";
cin >> hourly;
cout << "Enter number of hours worked: ";
cin >> hours;
cout.setf(ios::showpoint);
cout.setf(ios::fixed, ios::floatfield);
cout.setf(ios::right, ios::adjustfield);
// or cout << showpoint << fixed << right;
cout << "First format:\n";
cout << setw(30) << name << ": $" << setprecision(2)
<< setw(10) << hourly << ":" << setprecision(1)
<< setw(5) << hours << "\n";
cout << "Second format:\n";
cout.setf(ios::left, ios::adjustfield);
cout << setw(30) << name << ": $" << setprecision(2)
<< setw(10) << hourly << ":" << setprecision(1)
<< setw(5) << hours << "\n";
return 0;
}
08. Consider the following program:
// rq17-8.cpp
#include <iostream>
int main()
{
using namespace std;
char ch;
int ct1 = 0;
cin >> ch;
while (ch != 'q')
{
ct1++;
cin >> ch;
}
int ct2 = 0;
cin.get(ch);
while (ch != 'q')
{
ct2++;
cin.get(ch);
}
cout << "ct1 = " << ct1 << "; ct2 = " << ct2 << "\n";
return 0;
}
What does it print, given the following input:
Here signifies pressing the Enter key.
It will print:
`ct1 = 5; ct2 = 8`
// Answer in the book
Here is the output:
`ct1 = 5; ct2 = 9`
The first part of the program ignores spaces and newline characters; the second part
doesn’t. Note that the second part of the program begins reading at the newline
character following the first q, and it counts that newline character as part of its
total.
// rq17-8.cpp
#include <iostream>
int main()
{
using namespace std;
char ch;
int ct1 = 0;
cin >> ch;
while (ch != 'q')
{
ct1++;
cin >> ch;
}
int ct2 = 0;
cin.get(ch);
while (ch != 'q')
{
ct2++;
cin.get(ch);
}
cout << "ct1 = " << ct1 << "; ct2 = " << ct2 << "\n";
return 0;
}
09. Both of the following statements read and discard characters up to and including the end of a line. In what way does the behavior of one differ from that of the other?
`cin.ignore` discard `80` characters up to `\n` or eof condition; this `while` loop will discard characters until `\n` occur; // Answer in the book The `ignore()` form falters if the input line exceeds 80 characters. In that case, it skips only the first 80 characters.Chapter 18
01. Rewrite the following code using braced initialization list syntax; the rewrite
should dispense with using the array ar:
class Z200
{
private:
int j;
char ch;
double z;
public:
Z200(int jv, char chv, zv) : j(jv), ch(chv), z(zv){}...
};
double x = 8.8;
std::string s = "What a bracing effect!";
int k(99);
Z200 zip(200, 'Z', 0.675);
std::vector<int> ai(5);
int ar[5] = {3, 9, 4, 7, 1};
for (auto pt = ai.begin(), int i = 0; pt != ai.end(); ++pt, ++i)
*pt = ai[i];
class Z200
{
private:
int j;
char ch;
double z;
public:
Z200(int jv, char chv, zv) : j(jv), ch(chv), z(zv){}...
};
double x = 8.8;
std::string s = "What a bracing effect!";
int k(99);
Z200 zip(200, 'Z', 0.675);
std::vector<int> ai(5);
int ar[5] = {3, 9, 4, 7, 1};
for (auto pt = ai.begin(), int i = 0; pt != ai.end(); ++pt, ++i)
*pt = ai[i];
#include <iostream>
#include <vector>
class Z200
{
private:
int j;
char ch;
double z;
public:
Z200(int jv, char chv, double zv) : j(jv), ch(chv), z(zv){};
};
int main()
{
double x{8.8};
std::string s {"What a bracing effect!"};
int k{99};
Z200 zip{200, 'Z', 0.675};
std::vector<int> ai{5};
int ar[5] {3, 9, 4, 7, 1};
for (auto pt {ai.begin()}, int i{0}; pt != ai.end(); ++pt, ++i)
*pt = ai[i];
}
02. For the following short program, which function calls are errors and why? For the
valid calls, what does the reference argument refer to?
#include <iostream>
using namespace std;
double up(double x) { return 2.0 * x; }
void r1(const double &rx) { cout << rx << endl; }
void r2(double &rx) { cout << rx << endl; }
void r3(double &&rx) { cout << rx << endl; }
int main()
{
double w = 10.0;
r1(w);
r1(w + 1);
r1(up(w));
r2(w);
r2(w + 1);
r2(up(w));
r3(w);
r3(w + 1);
r3(up(w));
return 0;
}
#include <iostream>
using namespace std;
double up(double x) { return 2.0 * x; }
void r1(const double &rx) { cout << rx << endl; }
void r2(double &rx) { cout << rx << endl; }
void r3(double &&rx) { cout << rx << endl; }
int main()
{
double w = 10.0;
r1(w);
r1(w + 1);
r1(up(w));
r2(w);
r2(w + 1);
r2(up(w));
r3(w);
r3(w + 1);
r3(up(w));
return 0;
}
r2(w + 1); // reference need argument to bo to lvalue
r2(up(w)); // -||-
r3(w); // for &&, argument need to be rvalue
r1(w) is valid, and the argument rx refers to w.
r1(w+1) is valid, and the argument rx refers to a temporary initialized to the value
of w+1.
r1(up(w)) is valid, and the argument rx refers to a temporary initialized to the
return value of up(w).
In general, if an lvalue is passed to a const lvalue reference parameter, the parameter
is initialized to the lvalue. If an rvalue is passed to the function, a const lvalue
reference parameter refers to a temporary copy of the value.
r2(w) is valid, and the argument rx refers to w.
r2(w+1) is an error because w+1 is an rvalue.
r2(up(w)) is an error because the return value of up(w) is an rvalue.
In general, if an lvalue is passed to a non-const lvalue reference parameter, the
parameter is initialized to the lvalue. But a non-const lvalue reference parameter
can’t accept an rvalue function argument.
r3(w) is an error because an rvalue reference cannot refer to an lvalue, such as w.
r3(w+1) is valid, and rx refers to the temporary value of the expression w+1.
r3(up(w)) is valid, and rx refers to the temporary return value of up(w)
03.
a. What does the following short program display and why?
#include <iostream>
using namespace std;
double up(double x) { return 2.0 * x; }
void r1(const double &rx) { cout << “const double & rx\n”; }
void r1(double &rx) { cout << “double & rx\n”; }
int main()
{
double w = 10.0;
r1(w);
r1(w + 1);
r1(up(w));
return 0;
}
b. What does the following short program display and why?
c. What does the following short program display and why?
a)
b)
c)
// Answer in the book
#include <iostream>
using namespace std;
double up(double x) { return 2.0 * x; }
void r1(const double &rx) { cout << “const double & rx\n”; }
void r1(double &rx) { cout << “double & rx\n”; }
int main()
{
double w = 10.0;
r1(w);
r1(w + 1);
r1(up(w));
return 0;
}
a.
double & rx
const double & rx
const double & rx
The non-const lvalue reference matches the lvalue argument w. The other two
arguments are rvalues, and the const lvalue reference can refer to copies of them.
b.
double & rx
double && rx
double && rx
The lvalue reference matches the lvalue argument w, and the rvalue references
matches the two rvalue arguments.
c.
const double & rx
double && rx
double && rx
The const lvalue reference matches the lvalue argument w, and the rvalue reference
matches the two rvalues.
In short, a non-const lvalue parameter matches an lvalue argument, a non-const
rvalue parameter matches an rvalue argument, and a const lvalue parameter can
match either an lvalue or an rvalue argument, but the compiler will prefer the first
two choices, if available.
04. Which member functions are special member functions, and what makes them special?
// Answer in the book They are the default constructor, the copy constructor, the move constructor, the destructor, the copy assignment operator, and the move assignment operator. They are special because the compiler can automatically provide defaulted versions of these functions, depending on the context.05. Suppose the Fizzle class has only the data members shown: Why would this class not be a good candidate for a user-defined move constructor? What change in approach to storing the 4000 double values would make the class a good candidate for a move function?
Make bubbles a dynamic pointer for move semantics // Answer in the book A move constructor can be used when it makes sense to transfer ownership of data instead of copying it, but there is no mechanism for transferring ownership of a standard array. If the `Fizzle` class used a pointer and dynamic memory allocation, then one can transfer ownership by reassigning the address of the data to a new pointer.
06. Revise the following short program so that it uses a lambda expression instead of
f1(). Don’t change show2().
#include <iostream>
template <typename T>
void show2(double x, T &fp) { std::cout << x << " -> " << fp(x) << '\n'; }
int main()
{
show2(18.0, [] (double x)->double{return 1.8 * x + 32;} );
return 0;
}
// Answer in the book</br>
```cpp
#include <iostream>
#include <algorithm>
template<typename T>
void show2(double x, T fp) {std::cout << x << " -> " << fp(x) << '\n';}
int main()
{
show2(18.0, [](double x){return 1.8*x + 32;});
return 0;
}
07. Revise the following short and ugly program so that it uses a lambda expression
instead of the Adder functor. Don’t change sum().
#include <iostream>
#include <array>
const int Size = 5;
template <typename T>
void sum(std::array<double, Size> a, T &fp);
class Adder
{
double tot;
public:
Adder(double q = 0) : tot(q) {}
void operator()(double w) { tot += w; }
double tot_v() const { return tot; };
};
int main()
{
double total = 0.0;
Adder ad(total);
std::array<double, Size> temp_c = {32.1, 34.3, 37.8, 35.2, 34.7};
sum(temp_c, ad);
total = ad.tot_v();
std::cout << "total: " << ad.tot_v() << '\n';
return 0;
}
template <typename T>
void sum(std::array<double, Size> a, T &fp)
{
for (auto pt = a.begin(); pt != a.end(); ++pt)
{
fp(*pt);
}
}
#include <iostream>
#include <array>
const int Size = 5;
template <typename T>
void sum(std::array<double, Size> a, T &fp);
class Adder
{
double tot;
public:
Adder(double q = 0) : tot(q) {}
void operator()(double w) { tot += w; }
double tot_v() const { return tot; };
};
int main()
{
double total = 0.0;
Adder ad(total);
std::array<double, Size> temp_c = {32.1, 34.3, 37.8, 35.2, 34.7};
sum(temp_c, ad);
total = ad.tot_v();
std::cout << "total: " << ad.tot_v() << '\n';
return 0;
}
template <typename T>
void sum(std::array<double, Size> a, T &fp)
{
for (auto pt = a.begin(); pt != a.end(); ++pt)
{
fp(*pt);
}
}
#include <iostream>
#include <array>
const int Size = 5;
template <typename T>
void sum(std::array<double, Size> a, T &fp);
int main()
{
double total = 0.0;
std::array<double, Size> temp_c = {32.1, 34.3, 37.8, 35.2, 34.7};
sum(temp_c, [&](double w){total += w});
std::cout << "total: " << total << '\n';
return 0;
}
template <typename T>
void sum(std::array<double, Size> a, T &fp)
{
for (auto pt = a.begin(); pt != a.end(); ++pt)
{
fp(*pt);
}
}
#include <iostream>
#include <array>
#include <algorithm>
const int Size = 5;
template <typename T>
void sum(std::array<double, Size> a, T &fp);
int main()
{
double total = 0.0;
std::array<double, Size> temp_c = {32.1, 34.3, 37.8, 35.2, 34.7};
sum(temp_c, [&total](double w)
{ total += w; });
std::cout << "total: " << total << '\n';
std::cin.get();
return 0;
}
template <typename T>
void sum(std::array<double, Size> a, T &fp)
{
for (auto pt = a.begin(); pt != a.end(); ++pt)
{
fp(*pt);
}
}
Exercises
Chapter 2
1 - Write a C++ program that displays your name and address (or if you value your privacy,a fictitious name and address).
Code
#include <iostream> // a PREPROCESSOR directive
int main() // function header
{ // start of function body
using namespace std; // make definitions visible
cout << "Name: Deimos\n";
cout << "Country: Poland\n";
cout << "City: Warsaw";
cout << endl; // start a new line
return 0; // terminate main()
} // end of function body
2 - Write a C++ program that asks for a distance in furlongs and converts it to yards. (One furlong is 220 yards.)
Code
#include <iostream> // a PREPROCESSOR directive
int main() // function header
{ // start of function body
using namespace std; // make definitions visible
float iFurlongs = 0; // declare variables
float iYards = 0;
cout << "Program converting distance from furlong to yards\n";
cout << "1 furlong = 220 yards\n\n";
cout << "Enter the distance in furlongs: ";
cin >> iFurlongs; // read input
cout << iFurlongs << " furlongs = " << iFurlongs * 220 << " yards";
cout << endl; // start a new line
return 0; // terminate main()
} // end of function body
3 -
Write a C++ program that uses three user-defined functions
(counting main() as one) and produces the following output:
One function,called two times,should produce the first two lines, and the remain- ing function, also called twice, should produce the remaining output.
Code
#include <iostream> // a PREPROCESSOR directive
using namespace std;
void fun1()
{
cout << "Three blind mice\n";
}
void fun2()
{
cout << "See how they run\n";
}
int main() // function header
{ // start of function body
fun1(); // function call
fun1(); // function call
fun2(); // function call
fun2(); // function call
return 0; // terminate main()
}
4 - Write a program that asks the user to enter his or her age. The program then should display the age in months:
Code
5 -
Write a program that has main() call a user-defined function that takes a
Celsius temperature value as an argument and then returns the equivalent
Fahrenheit value.The program should request the Celsius value as input from
the user and displaythe result, as shown in the following code:
For reference,here is the formula for making the conversion:
Fahrenheit = 1.8 × degrees Celsius + 32.0
Code
#include <iostream> // a PREPROCESSOR directive
float fnCelsiusToFahrenheit(float fCelsius)
{
return (1.8 * fCelsius + 32);
}
int main() // function header
{
using namespace std;
float fCelsius = 0;
cout << "\nPlease enter a Celsius value: ";
cin >> fCelsius;
cout << fCelsius << " degrees Celsius is " << fnCelsiusToFahrenheit(fCelsius) << " degrees Farhenheit\n";
return 0; // terminate main()
}
6 -
Write a program that has main() call a user-defined function that takes
a distance in light years as an argument and then returns the distance
in astronomical units.The program should request the light year value as
input from the user and display the result,as shown in the following code:
An astronomical unit is the average distance from the earth to the sun (about 150,000,000 km or 93,000,000 miles), and a light year is the distance light travels in a year (about 10 trillion kilometers or 6 trillion miles). (The nearest star after thesun is about 4.2 light years away.) Use type double (as in Listing 2.4 (page 51)) and this conversion factor:
Code
#include <iostream> // a PREPROCESSOR directive
int main() // function header
{
using namespace std;
double dLightYears = 0;
cout << "\nEnter the number of light years: ";
cin >> dLightYears;
cout << dLightYears << " light years = " << (dLightYears * 63240) << " astronomical units\n";
return 0; // terminate main()
}
7 -
Write a program that asks the user to enter an hour value and a minute value.
The main() function should then pass these two values to a type void
function that displays the two values in the format shown in the following
sample run:
Code
#include <iostream> // a PREPROCESSOR directive
int main() // function header
{
using namespace std;
int iHours = 0;
int iMinutes = 0;
cout << "\nEnter the number of hours: ";
cin >> iHours;
cout << "Enter the number of minutes: ";
cin >> iMinutes;
cout << "Time: " << iHours << ":" << iMinutes << endl;
return 0; // terminate main()
}
Chapter 3
1 - Write a short program that asks for your height in integer inches and then converts your height to feet and inches. Have the program use the underscore character to indicate where to type the response. Also use a const symbolic constant to represent the conversion factor.
Code
#include <iostream>
const unsigned int _CONV_FACTOR {12};
int main()
{
using namespace std;
unsigned int uiHeightInput {0};
unsigned int uiHeightFeet {0};
unsigned int uiHeightInches {0};
cout << "Enter your height in inches:__\b\b";
cin >> uiHeightInput;
uiHeightFeet = uiHeightInput / _CONV_FACTOR;
uiHeightInches = uiHeightInput % _CONV_FACTOR;
cout << "Your height is: " << uiHeightFeet << " feet and " << uiHeightInches << " inches." << endl;
}
2 -
Write a short program that asks for your height in feet and inches and your weight in pounds. (Use three variables to store the information.) Have the program report your body mass index (BMI).To calculate the BMI, first convert your height in feet and inches to your height in inches (1 foot = 12 inches). Then convert your height in inches to your height in meters by multiplying by 0.0254.Then convert your weight in pounds into your mass in kilograms by dividing by 2.2. Finally, compute your BMI by dividing your mass in kilograms by the square of your height in meters. Use symbolic constants to represent the various conversion factors.
Code
#include <iostream>
const int _RATIO_FEET_TO_INCH {12};
const float _RATIO_INCH_TO_METER {0.0254};
const float _CONV_POUNDS_TO_KG {2.2};
double fnBMI(double dHeight, double dWeight); // function prototype
int main()
{
using namespace std;
unsigned int uiHeightFeet {};
double ulHeightInches {};
double ulWeight {};
cout << "Enter your height in feet and (the rest) in inches. Round to whole units.\n";
cout << "Enter your height in feet:__\b\b";
cin >> uiHeightFeet;
cout << "Enter your height in inches:__\b\b";
cin >> ulHeightInches;
cout << "Enter your weight in pounds:__\b\b";
cin >> ulWeight;
ulHeightInches = (uiHeightFeet * _RATIO_FEET_TO_INCH) + ulHeightInches; // height in inches
cout << "\nYour height in inches is " << ulHeightInches << endl;
cout << "Your BMI is " << fnBMI(ulHeightInches, ulWeight) << endl;
}
/// @brief BMI calculator
/// @param dHeight in inches
/// @param dWeight in pounds
/// @return BMI value in double
double fnBMI(double dHeight, double dWeight)
{
dHeight = dHeight * _RATIO_INCH_TO_METER; // height in meters
std::cout << "Your height in meters is " << dHeight << std::endl;
dWeight = dWeight / _CONV_POUNDS_TO_KG; // weight in kilograms
std::cout << "Your weight in kilograms is " << dWeight << std::endl << std::endl;
return dWeight / (dHeight * dHeight);
}
3 - Write a program that asks the user to enter a latitude in degrees, minutes, and seconds and that then displays the latitude in decimal format.There are 60 seconds of arc to a minute and 60 minutes of arc to a degree; represent these values with symbolic constants.You should use a separate variable for each input value. A sample run should look like this:
Enter a latitude in degrees, minutes, and seconds:
First, enter the degrees: 37
Next, enter the minutes of arc: 51
Finally, enter the seconds of arc: 19
37 degrees, 51 minutes, 19 seconds = 37.8553 degrees
Code
#include <iostream>
const int _CONV_ARCSECONDS_TO_ARCMINUTES {60};
const int _CONV_ARCMINUTES_TO_DEGREES {60};
double fnDecimalLattitude(int iDegrees, int iArcMinutes, int iArcSeconds);
int main()
{
using namespace std;
int iDegrees {};
int iArcMinutes {};
int iArcSeconds {};
cout << "Enter a latitude in degrees, minutes, and seconds:\n";
cout << "First, enter the degrees: ";
cin >> iDegrees;
cout << "Next, enter the minutes of arc: ";
cin >> iArcMinutes;
cout << "Finally, enter the seconds of arc: ";
cin >> iArcSeconds;
cout << iDegrees << " degrees, " << iArcMinutes << " minutes, " << iArcSeconds << " seconds = ";
cout << fnDecimalLattitude(iDegrees, iArcMinutes, iArcSeconds) << " degrees\n";
}
/// @brief Returns the latitude with decimal format
double fnDecimalLattitude(int iDegrees, int iArcMinutes, int iArcSeconds)
{
double dDegrees = double(iArcSeconds) / _CONV_ARCSECONDS_TO_ARCMINUTES;
dDegrees = (iArcMinutes + dDegrees) / _CONV_ARCMINUTES_TO_DEGREES;
return iDegrees + dDegrees;
}
4 - Write a program that asks the user to enter the number of seconds as an integer value (use type long, or, if available, long long) and that then displays the equivalent time in days, hours, minutes, and seconds. Use symbolic constants to represent the number of hours in the day, the number of minutes in an hour, and the number of seconds in a minute.The output should look like this:
Code
#include <iostream>
const int _CONV_SECONDS_TO_MINUTES {60};
const int _CONV_MINUTES_TO_HOURS {60};
const int _CONV_HOURS_TO_DAYS {24};
int main()
{
using namespace std;
unsigned long long llInputSeconds {}, llSeconds {};
unsigned long iMinutes {}, iHours {}, iDays {};
cout << "Enter the number of seconds: ";
cin >> llInputSeconds;
iMinutes = llInputSeconds / _CONV_SECONDS_TO_MINUTES;
llSeconds = llInputSeconds % iMinutes;
iHours = iMinutes / _CONV_MINUTES_TO_HOURS;
iMinutes = iMinutes % iHours;
iDays = iHours / _CONV_HOURS_TO_DAYS;
iHours = iHours % iDays;
cout << llInputSeconds << " seconds = " << iDays << " days, " << iHours << " hours, " << iMinutes << " minutes, " << llSeconds << " seconds\n";
}
5 - Write a program that requests the user to enter the current world population and the current population of the U.S. (or of some other nation of your choice). Store the information in variables of type long long. Have the program display the percent that the U.S. (or other nation’s) population is of the world’s population.The output should look something like this:
Enter the world's population: 6898758899
Enter the population of the US: 310783781
The population of the US is 4.50492% of the world population.
You can use the Internet to get more recent figures.
Code
#include <iostream>
int main()
{
using namespace std;
unsigned long long llWorldPopulation {};
unsigned long long llCountryPopulation {};
cout << "Enter the world's population: ";
cin >> llWorldPopulation;
cout << "Enter the population of the US: ";
cin >> llCountryPopulation;
cout << "The population of the US is ";
cout << (double)llCountryPopulation / llWorldPopulation * 100;
cout << "% of the world population.";
}
6 - Write a program that asks how many miles you have driven and how many gallons of gasoline you have used and then reports the miles per gallon your car has gotten. Or, if you prefer, the program can request distance in kilometers and petrol in liters and then report the result European style, in liters per 100 kilometers.
Code
#include <iostream>
int main()
{
using namespace std;
unsigned long long llMilesDriven {};
unsigned long long llUsedGasoline {};
cout << "Enter how many miles you have driven: ";
cin >> llMilesDriven;
cout << "Enter how many gallons of gasoline you have used: ";
cin >> llUsedGasoline;
cout << (double)llMilesDriven / llUsedGasoline;
cout << " miles per gallon your car have gotten";
}
7 - Write a program that asks you to enter an automobile gasoline consumption figure in the European style (liters per 100 kilometers) and converts to the U.S. style of miles per gallon. Note that in addition to using different units of measurement, the U.S. approach (distance / fuel) is the inverse of the European approach (fuel / distance). Note that 100 kilometers is 62.14 miles, and 1 gallon is 3.875 liters. Thus, 19 mpg is about 12.4 l/100 km, and 27 mpg is about 8.7 l/100 km.
Code
#include <iostream>
const double _RATIO_KM_TO_M {0.6214};
const double _RATIO_GAL_TO_L {3.785412};
int main()
{
using namespace std;
float fGasolineConsumptionEU {};
cout << "Enter automobile gasoline consumption figure (liters per 100 kilometers): ";
cin >> fGasolineConsumptionEU;
cout << fGasolineConsumptionEU << " liters per 100 kilometers = ";
cout << fGasolineConsumptionEU / _RATIO_GAL_TO_L << " galons per ";
cout << _RATIO_KM_TO_M * 100 << " miles\n";
cout << "MPG = " << (_RATIO_KM_TO_M * 100) / (fGasolineConsumptionEU / _RATIO_GAL_TO_L) << endl;
}
Chapter 4
1 - Write a C++ program that requests and displays information as shown in the following.
Example of output:
What is your first name? Betty Sue
What is your last name? Yewe
What letter grade do you deserve? B
What is your age? 22
Name: Yewe, Betty Sue
Grade: C
Age: 22
Note that the program should be able to accept first names that comprise more than one word. Also note that the program adjusts the grade downward—that is, up one letter. Assume that the user requests an A, a B, or a C so that you don’t have to worry about the gap between a D and an F.
Code
#include <iostream>
const double _RATIO_KM_TO_M {0.6214};
const double _RATIO_GAL_TO_L {3.785412};
int main()
{
using namespace std;
float fGasolineConsumptionEU {};
cout << "Enter automobile gasoline consumption figure (liters per 100 kilometers): ";
cin >> fGasolineConsumptionEU;
cout << fGasolineConsumptionEU << " liters per 100 kilometers = ";
cout << fGasolineConsumptionEU / _RATIO_GAL_TO_L << " galons per ";
cout << _RATIO_KM_TO_M * 100 << " miles\n";
cout << "MPG = " << (_RATIO_KM_TO_M * 100) / (fGasolineConsumptionEU / _RATIO_GAL_TO_L) << endl;
}
2 - Rewrite Listing 4.4, using the C++ string class instead of char arrays.
Code
#include <iostream>
#include <string>
struct stStudent {
std::string firstName;
std::string lastName;
char Grade;
unsigned int age;
};
int main()
{
using namespace std;
stStudent *pStudent = new stStudent;
cout << "What is your first name? ";
getline(cin, pStudent->firstName);
cout << "What is your last name? ";
getline(cin, pStudent->lastName);
cout << "What letter grade do you deserve? ";
cin >> pStudent->Grade;
cout << "What is your age? ";
cin >> pStudent->age;
cout << "Name: " << pStudent->lastName << ", " << pStudent->firstName << endl;
cout << "Grade: " << (char) ++(pStudent->Grade) << endl;
cout << "Age: " << pStudent->age << endl;
return 0;
}
3 - Write a program that asks the user to enter his or her first name and then last name, and that then constructs, stores, and displays a third string, consisting of the user’s last name followed by a comma, a space, and first name. Use char arrays and functions from the cstring header file.A sample run could look like this:
Enter your first name: Flip
Enter your last name: Fleming
Here’s the information in a single string: Fleming, Flip
Code
#include <iostream>
#include <cstring>
int main()
{
using namespace std;
char szFirstName[50];
char szLastName[50];
char szConNames[100];
cout << "Enter your first name: ";
cin.getline(szFirstName, 50);
cout << "Enter your last name: ";
cin.getline(szLastName, 50);
cout << "Here is the information in a single string: ";
strcpy(szConNames, szLastName);
strcat(szConNames, ", ");
strcat(szConNames, szFirstName);
cout << szConNames << endl;
return 0;
}
4 - Write a program that asks the user to enter his or her first name and then last name, and that then constructs, stores, and displays a third string consisting of the user’s last name followed by a comma, a space, and first name. Use string objects and methods from the string header file. A sample run could look like this:
Enter your first name: Flip
Enter your last name: Fleming
Here’s the information in a single string: Fleming, Flip
Code
#include <iostream>
#include <string>
int main()
{
using namespace std;
string szFirstName;
string szLastName;
string szConNames;
cout << "Enter your first name: ";
getline(cin, szFirstName);
cout << "Enter your last name: ";
getline(cin, szLastName);
cout << "Here is the information in a single string: ";
szConNames = szLastName + ", " + szFirstName;
cout << szConNames << endl;
return 0;
}
5 - The CandyBar structure contains three members. The first member holds the brand name of a candy bar. The second member holds the weight (which may have a fractional part) of the candy bar, and the third member holds the number of calories (an integer value) in the candy bar. Write a program that declares such a structure and creates a CandyBar variable called snack, initializing its members to "Mocha Munch", 2.3, and 350, respectively.The initialization should be part of the declaration for snack. Finally, the program should display the contents of the snack variable.
Code
#include <iostream>
struct CandyBar{
char name[20];
float weight;
int calories;
};
int main()
{
using namespace std;
CandyBar snack {"Mocha Munch", 2.3, 350};
cout << "Snack name: " << snack.name << endl
<< "Snack weight: " << snack.weight << endl
<< "Snack calories: " << snack.calories << endl;
return 0;
}
6 - The CandyBar structure contains three members, as described in Programming Exercise 5.Write a program that creates an array of three CandyBar structures, initializes them to values of your choice, and then displays the contents of each structure.
Code
#include <iostream>
struct CandyBar{
char name[20];
float weight;
int calories;
};
int main()
{
using namespace std;
CandyBar snack[3];
snack[0] = {"Mocha Munch", 2.3, 350};
snack[1] = {"Nom Nom Nom", 4.5, 440};
snack[2] = {"Diet Munch", 5.3, 600};
// // Also correct
// snack[3] =
// {
// {"Mocha Munch", 2.3, 350};
// {"Nom Nom Nom", 4.5, 440};
// {"Diet Munch", 5.3, 600}
// };
cout << "Snack name: " << snack[0].name << endl
<< "Snack weight: " << snack[0].weight << endl
<< "Snack calories: " << snack[0].calories << endl << endl;
cout << "Snack name: " << snack[1].name << endl
<< "Snack weight: " << snack[1].weight << endl
<< "Snack calories: " << snack[1].calories << endl << endl;
cout << "Snack name: " << snack[2].name << endl
<< "Snack weight: " << snack[2].weight << endl
<< "Snack calories: " << snack[2].calories << endl << endl;
return 0;
}
7 - William Wingate runs a pizza-analysis service. For each pizza, he needs to record the following information:
- The name of the pizza company, which can consist of more than one word
- The diameter of the pizza
- The weight of the pizza
Devise a structure that can hold this information and write a program that uses a structure variable of that type.The program should ask the user to enter each of the preceding items of information, and then the program should display that information. Use cin (or its methods) and cout.
Code
#include <iostream>
struct Pizza{
char name[50];
float diameter;
float weight;
};
int main()
{
using namespace std;
Pizza myPizza;
cout << "Enter the name of your pizza: ";
cin.getline(myPizza.name, 50);
cout << "Enter the diameter of your pizza: ";
cin >> myPizza.diameter;
cout << "Enter the weight of your pizza: ";
cin >> myPizza.weight;
cout << endl << "My Pizza name: " << myPizza.name << endl
<< "My Pizza diameter: " << myPizza.diameter << endl
<< "My Pizza weight: " << myPizza.weight << endl << endl;
return 0;
}
8 - Do Programming Exercise 7 but use new to allocate a structure instead of declaring a structure variable. Also have the program request the pizza diameter before it requests the pizza company name.
Code
#include <iostream>
#include <cstring>
struct Pizza
{
char name[50];
float diameter;
float weight;
};
int main()
{
using namespace std;
Pizza *myPizza = new Pizza;
cout << "Enter the diameter of your pizza: ";
// cin leaves a newline character in the input stream .get removes it (chapter 3: C-style strings)
(cin >> myPizza->diameter).get();
cout << "Enter the name of your pizza: ";
cin.getline(myPizza->name, 50);
cout << "Enter the weight of your pizza: ";
cin >> myPizza->weight;
cout << endl
<< "My Pizza name: " << myPizza->name << endl
<< "My Pizza diameter: " << myPizza->diameter << endl
<< "My Pizza weight: " << myPizza->weight << endl
<< endl;
delete myPizza;
return 0;
}
9 - Do Programming Exercise 6, but instead of declaring an array of three CandyBar structures, use new to allocate the array dynamically.
Code
#include <iostream>
struct CandyBar
{
char name[20];
float weight;
int calories;
};
int main()
{
using namespace std;
CandyBar *snack = new CandyBar[3];
snack[0] = {"Mocha Munch", 2.3, 350};
snack[1] = {"Nom Nom Nom", 4.5, 440};
snack[2] = {"Diet Munch", 5.3, 600};
cout << "Snack name: " << snack[0].name << endl
<< "Snack weight: " << snack[0].weight << endl
<< "Snack calories: " << snack[0].calories << endl
<< endl;
cout << "Snack name: " << snack[1].name << endl
<< "Snack weight: " << snack[1].weight << endl
<< "Snack calories: " << snack[1].calories << endl
<< endl;
cout << "Snack name: " << snack[2].name << endl
<< "Snack weight: " << snack[2].weight << endl
<< "Snack calories: " << snack[2].calories << endl
<< endl;
delete[] snack;
return 0;
}
10 - Write a program that requests the user to enter three times for the 40-yd dash (or 40-meter, if you prefer) and then displays the times and the average. Use an array object to hold the data. (Use a built-in array if array is not available.)
Code
Chapter 5
1 - Write a program that requests the user to enter two integers.The program should then calculate and report the sum of all the integers between and including the two integers. At this point, assume that the smaller integer is entered first. For example, if the user enters 2 and 9, the program should report that the sum of all the integers from 2 through 9 is 44.
Code
#include <iostream>
int main()
{
using namespace std;
int iVal[2] {}, iSum {};
cout << "Enter two integers: " << endl;
cout << " First integer: ";
cin >> iVal[0];
cout << " Second integer: ";
cin >> iVal[1];
if (iVal[0] > iVal[1]){
int temp {};
temp = iVal[0];
iVal[0] = iVal[1];
iVal[1] = temp;
}
for (size_t i = iVal[0]; i <= iVal[1]; i++)
iSum += i;
cout << "Sum of integers from " << iVal[0] << " to " << iVal[1] << " is " << iSum << endl;
return 0;
}
2 - Redo Listing 5.4 using a type array object instead of a built-in array and type long double instead of long long. Find the value of 100!
Code
#include <iostream>
#include <array>
int main()
{
using namespace std;
array<long double, 2> dVal {};
long double dSum {};
cout << "Enter two integers: " << endl;
cout << " First integer: ";
cin >> dVal[0];
cout << " Second integer: ";
cin >> dVal[1];
if (dVal[0] > dVal[1]){
int temp {};
temp = dVal[0];
dVal[0] = dVal[1];
dVal[1] = temp;
}
for (size_t i = dVal[0]; i <= dVal[1]; i++)
dSum += i;
cout << "Sum of integers from " << dVal[0] << " to " << dVal[1] << " is " << dSum << endl;
return 0;
}
3 - Write a program that asks the user to type in numbers.After each entry, the program should report the cumulative sum of the entries to date.The program should terminate when the user enters 0.
Code
#include <iostream>
int main()
{
using namespace std;
long double dVal {}, dSum {};
cout << "Enter a number, the program will sum it all.\n";
cout << "Enter 0 to exit.\n\n";
do{
cout << "Enter a number : ";
cin >> dVal;
dSum += dVal;
cout << "Sum : " << dSum << endl;
}while (dVal != 0);
cout << "Bye!\n";
return 0;
}
4 -
Daphne invests $100 at 10% simple interest.That is, every year, the investment earns
10% of the original investment, or $10 each and every year:
At the same time, Cleo invests $100 at 5% compound interest.That is, interest is 5%
of the current balance, including previous additions of interest:
Cleo earns 5% of $100 the first year, giving her $105.The next year she earns 5% of
$105, or $5.25, and so on. Write a program that finds how many years it takes for
the value of Cleo’s investment to exceed the value of Daphne’s investment and then
displays the value of both investments at that time.
Code
#include <iostream>
int main()
{
using namespace std;
double dSimple {100}, dCompound {100};
double dSimpleSum {dSimple}, dCompoundSum {dCompound};
size_t i {0};
cout << "\nInitial investment in 10% Simple interest: " << dSimple << endl;
cout << "Initial investment in 5% Compound interest: " << dCompound << endl << endl;
do
{
i++;
dSimpleSum += dSimple * 0.1;
dCompoundSum += dCompoundSum * 0.05;
} while (dSimpleSum > dCompoundSum);
cout << "Simple Interest after " << i << " years: " << dSimpleSum << endl;
cout << "Compound Interest after " << i << " years: " << dCompoundSum << endl;
cout << endl << " It takes " << i << " years for compound investment to exceed simple investment." << endl << endl;
return 0;
}
5 - You sell the book C++ for Fools. Write a program that has you enter a year’s worth of monthly sales (in terms of number of books, not of money).The program should use a loop to prompt you by month, using an array of char * (or an array of string objects, if you prefer) initialized to the month strings and storing the input data in an array of int.Then, the program should find the sum of the array contents and report the total sales for the year.
Code
#include <iostream>
#include <string>
int main()
{
using namespace std;
string sMonths[] {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"};
// const char *sMonths[12] { // also correct
// "January", "February", "March", "April", "May", "June",
// "July", "August", "September", "October", "November", "December"};
int iSales[12];
long lTotal {};
cout << "Enter monthly sale for a: \n";
for (size_t i = 0; i < 12; i++)
{
cout << sMonths[i] << ": ";
cin >> iSales[i];
lTotal += iSales[i];
}
cout << "\nTotal sales for the year: " << lTotal << endl;
return 0;
}
6 - Do Programming Exercise 5 but use a two-dimensional array to store input for 3 years of monthly sales. Report the total sales for each individual year and for the combined years.
Code
#include <iostream>
#include <string>
int main()
{
using namespace std;
string sMonths[]{
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"};
int iSales[3][12] {};
long lYearlyTotal[3] {};
long lTotal{};
for (size_t i = 0; i < 3; i++)
{
cout << "For " << (i + 1) << " year, enter the sale for: \n";
for (size_t j = 0; j < 12; j++)
{
cout << sMonths[j] << ": ";
cin >> iSales[i][j];
lYearlyTotal[i] += iSales[i][j];
}
lTotal += lYearlyTotal[i];
cout << "\nTotal sales for " << (i + 1) << " year: " << lYearlyTotal[i] << "\n";
}
cout << "\nTotal sales for all years: " << lTotal << endl;
return 0;
}
7 - Design a structure called car that holds the following information about an automobile: its make, as a string in a character array or in a string object, and the year it was built, as an integer.Write a program that asks the user how many cars to catalog. The program should then use new to create a dynamic array of that many car structures. Next, it should prompt the user to input the make (which might consist of more than one word) and year information for each structure. Note that this requires some care because it alternates reading strings with numeric data (see Chapter 4). Finally, it should display the contents of each structure.A sample run should look something like the following:
How many cars do you wish to catalog? 2
Car #1:
Please enter the make: Hudson Hornet
Please enter the year made: 1952
Car #2:
Please enter the make: Kaiser
Please enter the year made: 1951
Here is your collection:
1952 Hudson Hornet
1951 Kaiser
Code
#include <iostream>
#include <string>
struct car{
std::string make;
int year;
};
int main()
{
using namespace std;
int iNumCars{};
cout << "How many cars do you wish to catalog? : ";
(cin >> iNumCars).get();
car *pCar = new car[iNumCars];
for (size_t i = 0; i < iNumCars; i++)
{
cout << "Car #" << i + 1 << ":" << endl;
cout << "Please enter the make: ";
getline(cin, pCar[i].make);
cout << "Please enter the year made: ";
(cin >> pCar[i].year).get();
}
cout << "\nHere is your collection:\n";
for (size_t i = 0; i < iNumCars; i++)
cout << pCar[i].year << " " << pCar[i].make << endl;
return 0;
}
8 - Write a program that uses an array of char and a loop to read one word at a time until the word done is entered.The program should then report the number of words entered (not counting done).A sample run could look like this:
Enter words (to stop, type the word done):
anteater birthday category dumpster
envy finagle geometry done for sure
You entered a total of 7 words.
You should include the cstring header file and use the strcmp() function to make the comparison test.
Code
9 - Write a program that matches the description of the program in Programming Exercise 8, but use a string class object instead of an array. Include the string header file and use a relational operator to make the comparison test.
Code
10 - Write a program using nested loops that asks the user to enter a value for the number of rows to display. It should then display that many rows of asterisks, with one asterisk in the first row, two in the second row, and so on. For each row, the asterisks are preceded by the number of periods needed to make all the rows display a total number of characters equal to the number of rows.A sample run would look like this:
Code
#include <iostream>
#include <cstring>
int main()
{
using namespace std;
int iRows{};
cout << "Enter number of rows: ";
cin >> iRows;
for (size_t i = 0; i < iRows; i++) // lines to print
{
// dots to print:
// dot = 1, -> because per 3 chars there is one `star`
// dot < iRows - i, -> because the next line will have one more `star`
// and one less `dot` EVERY LOOP
for (size_t dot = 1; dot < iRows - i; ++dot) // DOTS ARE PRINTED FIRST
cout << ".";
for (size_t star = 0; star <= i; ++star) // STARS ARE PRINTED SECOND
cout << "*";
// // Different solution
// for (size_t dot = i; dot < iRows - 1; dot++)
// cout << '.';
// for (size_t star = i + 1; star != 0; star--)
// cout << '*';
cout << endl;
}
return 0;
}
Chapter 6
1 -
Write a program that reads keyboard input to the @ symbol and that echoes the input except for digits,
converting each uppercase character to lowercase, and vice versa. (Don’t forget the cctype family.)
Code
2 - Write a program that reads up to 10 donation values into an array of double. (Or, if you prefer, use an array template object.) The program should terminate input on non-numeric input. It should report the average of the numbers and also report how many numbers in the array are larger than the average.
Code
#include <iostream>
#include <cstdlib>
#include <cctype>
const int MAX_SIZE = 10;
int main()
{
using namespace std;
double dArray[MAX_SIZE]{};
double dAboveAverage{}, dSum{};
int i{};
cout << "Write " << MAX_SIZE << " donations: \n";
cout << "\n #" << i + 1 << " donation: ";
while (i < MAX_SIZE && cin >> dArray[i])
{
dSum += dArray[i];
if(++i < MAX_SIZE)
cout << " #" << i + 1 << " donation: ";
}
for (size_t j = 0; j < i; j++)
if (dArray[j] > (dSum / i))
++dAboveAverage;
cout << "\n\n Average from donations: " << dSum / i << endl;
cout << " Amount of donations above average: " << dAboveAverage << endl;
return 0;
}
3 - Write a precursor to a menu-driven program.The program should display a menu offering four choices, each labeled with a letter. If the user responds with a letter other than one of the four valid choices, the program should prompt the user to enter a valid response until the user complies.Then the program should use a switch to select a simple action based on the user’s selection. A program run could look something like this:
Please enter one of the following choices:
c) carnivore p) pianist
t) tree g) game
f
Please enter a c, p, t, or g: q
Please enter a c, p, t, or g: t
A maple is a tree.
Code
#include <iostream>
int main(){
using namespace std;
char cMenu;
cout << "Please enter one of the following choices:" << endl
<< "c) carnivore\t p) pianist" << endl
<< "t) tree\t\t g) game" << endl;
cin >> cMenu;
while(true){
switch (cMenu)
{
case 'c':
cout << "Cat is a carnivore.";
break;
case 'p':
cout << "Beethoven is a pianist";
break;
case 't':
cout << "A maple is a tree.";
break;
case 'g':
cout << "Rain World is a good game.";
break;
default:
cout << "Please enter a: c, p, t, or g: ";
break;
}
cin >> cMenu;
}
return 0;
}
4 - When you join the Benevolent Order of Programmers, you can be known at BOP meetings by your real name, your job title, or your secret BOP name. Write a program that can list members by real name, by job title, by secret name, or by a member’s preference. Base the program on the following structure:
// Benevolent Order of Programmers name structure
struct bop
{
char fullname[strsize]; // real name
char title[strsize]; // job title
char bopname[strsize]; // secret BOP name
int preference; // 0 = fullname, 1 = title, 2 = bopname
};
In the program, create a small array of such structures and initialize it to suitable values. Have the program run a loop that lets the user select from different alternatives:
Note that “display by preference” does not mean display the preference member; it means display the member corresponding to the preference number. For instance, if preference is 1, choice d would display the programmer’s job title.A sample run may look something like the following:
Benevolent Order of Programmers Report
a. display by name b. display by title
c. display by bopname d. display by preference
q. quit
Enter your choice: a
Wimp Macho
Raki Rhodes
Celia Laiter
Hoppy Hipman
Pat Hand
Next choice: d
Wimp Macho
Junior Programmer
MIPS
Analyst Trainee
LOOPY
Next choice: q
Bye!
Code
#include <iostream>
#include <cstring>
const int sizeBOP = 5;
const int strsize = 50;
// Benevolent Order of Programmers name structure
struct bop
{
char fullname[strsize]; // real name
char title[strsize]; // job title
char bopname[strsize]; // secret BOP name
int preference; // 0 = fullname, 1 = title, 2 = bopname
};
int main()
{
using namespace std;
char cMenu;
cout << "Please enter one of the following choices:" << endl
<< "a. display by name\t b. display by title" << endl
<< "c. display by bopname\t d. display by preference" << endl
<< "q. quit" << endl;
cout << "Enter your choice: ";
cin >> cMenu;
bop *stBOP = new bop[sizeBOP];
strcpy(stBOP[0].fullname, "Wimp Macho");
strcpy(stBOP[0].title, "Chef");
strcpy(stBOP[0].bopname, "BOPA");
stBOP[0].preference = 0;
strcpy(stBOP[1].fullname, "Raki Rhodes");
strcpy(stBOP[1].title, "Junior Programmer");
strcpy(stBOP[1].bopname, "RAKI");
stBOP[1].preference = 1;
strcpy(stBOP[2].fullname, "Celia Laiter");
strcpy(stBOP[2].title, "Senior Programmer");
strcpy(stBOP[2].bopname, "MIPS");
stBOP[2].preference = 2;
strcpy(stBOP[3].fullname, "Hoppy Hipman");
strcpy(stBOP[3].title, "Analyst trainee");
strcpy(stBOP[3].bopname, "MEHA");
stBOP[3].preference = 1;
strcpy(stBOP[4].fullname, "Pat Hand");
strcpy(stBOP[4].title, "Boss");
strcpy(stBOP[4].bopname, "LOOPY");
stBOP[4].preference = 2;
while (cMenu != 'q')
{
switch (cMenu)
{
case 'a':
for (int i{}; i < sizeBOP; ++i)
cout << stBOP[i].fullname << endl;
break;
case 'b':
for (int i{}; i < sizeBOP; ++i)
cout << stBOP[i].title << endl;
break;
case 'c':
for (int i{}; i < sizeBOP; ++i)
cout << stBOP[i].bopname << endl;
break;
case 'd':
for (int i{}; i < sizeBOP; ++i)
{
switch (stBOP[i].preference)
{
case 0: cout << stBOP[i].fullname << endl; break;
case 1: cout << stBOP[i].title << endl; break;
case 2: cout << stBOP[i].bopname << endl; break;
default: cout << "No preference" << endl; break;
}
}
break;
default:
cout << "Please enter: a, b, c, d, or q. : ";
break;
}
cout << "Next choice: ";
cin >> cMenu;
}
delete[] stBOP;
cout << "Bye!" << endl;
return 0;
}
5 - The Kingdom of Neutronia, where the unit of currency is the tvarp, has the following income tax code:
First 5,000 tvarps: 0% tax
Next 10,000 tvarps: 10% tax
Next 20,000 tvarps: 15% tax
Tvarps after 35,000: 20% tax
For example, someone earning 38,000 tvarps would owe 5,000 × 0.00 + 10,000 × 0.10 + 20,000 × 0.15 + 3,000 × 0.20, or 4,600 tvarps. Write a program that uses a loop to solicit incomes and to report tax owed. The loop should terminate when the user enters a negative number or non-numeric input.
Code
#include <iostream>
#include <cstdlib>
int main(){
using namespace std;
long double dIncome{}, dTax{};
cout << "Enter income in tvarps: ";
while(cin >> dIncome){
if(dIncome < 0)
break;
if (dIncome <= 5000)
dTax = 0;
else if(dIncome <= 15000)
dTax = (dIncome - 5000) * 0.1;
else if(dIncome < 35000)
dTax = (dIncome - 15000) * 0.15 + 10000 * 0.1;
else
dTax = (dIncome - 35000) * 0.2 + 20000 * 0.15 + 10000 * 0.1;
cout << "Your tax is: " << dTax << " tvarps" << endl;
cout << "Enter income in tvarps: ";
}
return 0;
}
6 -
Put together a program that keeps track of monetary contributions to the Society
for the Preservation of Rightful Influence. It should ask the user to enter
the number of contributors and then solicit the user to enter the name and
contribution of each contributor.The information should be stored in a dynamically
allocated array of structures. Each structure should have two members:
a character array (or else a string object) to store the name and a double
member to hold the amount of the contribution.After reading all the data,
the program should display the names and amounts donated for all donors
who contributed $10,000 or more. This list should be headed by the label
Grand Patrons.After that, the program should list the remaining donors.
That list should be headed Patrons. If there are no donors in one of the categories,
the program should print the word “none”. Aside from displaying two categories,
the program need do no sorting.
Code
#include <iostream>
#include <string>
struct stSocietyPRI
{
std::string name;
double contribution;
};
int main()
{
using namespace std;
int iContrbutors{}, iCounter{};
cout << "Enter the number of contributors: ";
while (!(cin >> iContrbutors))
{
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
cin.get(); // clear the input buffer
stSocietyPRI *pSociety = new stSocietyPRI[iContrbutors];
for (size_t i = 0; i < iContrbutors; i++)
{
cout << "Enter the name of the " << i + 1 << " contributor: ";
getline(cin, pSociety[i].name);
cout << "Enter the contribution of the " << i + 1 << " contributor: ";
while (!(cin >> pSociety[i].contribution))
{
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
cin.get(); // clear the input buffer
}
// Print Grand Patrons
iCounter = 0;
cout << "Grand Patrons: \n";
for (size_t i = 0; i < iContrbutors; i++)
{
if (pSociety[i].contribution >= 10000)
{
cout << "\t" << pSociety[i].name << "; \n";
++iCounter;
}
}
if (iCounter == 0)
cout << "\tnone\n";
// Print the rest Patrons
iCounter = 0;
cout << "Patrons: \n";
for (size_t i = 0; i < iContrbutors; i++)
{
if (pSociety[i].contribution < 10000)
{
cout << "\t" << pSociety[i].name << "; \n";
++iCounter;
}
}
if (iCounter == 0)
cout << "\tnone\n";
return 0;
}
7 -
Write a program that reads input a word at a time until a lone q is entered.
The program should then report the number of words that began with vowels,
the number that began with consonants, and the number that fit neither of
those categories. One approach is to use isalpha() to discriminate between
words beginning with letters and those that don’t and then use an if or switch
statement to further identify those passing the isalpha() test that begin with
vowels.A sample run might look like this:
Enter words (q to quit):
The 12 awesome oxen ambled
quietly across 15 meters of lawn. q
5 words beginning with vowels
4 words beginning with consonants
2 others
Code
#include <iostream>
#include <cstring>
#include <cctype>
int main()
{
using namespace std;
char cInput[100];
int iNumOther{}, iNumVowels{}, iNumConsonants{};
cout << "\nEnter words (q to quit):\n";
do
{
cin >> cInput;
if (!isalpha(cInput[0]))
{
++iNumOther;
}
else if (cInput[0] == 'A' || cInput[0] == 'E' ||
cInput[0] == 'I' || cInput[0] == 'O' ||
cInput[0] == 'U' || cInput[0] == 'Y' ||
cInput[0] == 'a' || cInput[0] == 'e' ||
cInput[0] == 'i' || cInput[0] == 'o' ||
cInput[0] == 'u' || cInput[0] == 'y')
{
++iNumVowels;
}
else if (cInput[0] == 'A' || cInput[0] == 'C' || cInput[0] == 'D' ||
cInput[0] == 'F' || cInput[0] == 'G' || cInput[0] == 'J' ||
cInput[0] == 'K' || cInput[0] == 'L' || cInput[0] == 'M' ||
cInput[0] == 'N' || cInput[0] == 'P' || cInput[0] == 'Q' ||
cInput[0] == 'S' || cInput[0] == 'T' || cInput[0] == 'V' ||
cInput[0] == 'X' || cInput[0] == 'Z' ||
cInput[0] == 'a' || cInput[0] == 'c' || cInput[0] == 'd' ||
cInput[0] == 'f' || cInput[0] == 'g' || cInput[0] == 'j' ||
cInput[0] == 'k' || cInput[0] == 'l' || cInput[0] == 'm' ||
cInput[0] == 'n' || cInput[0] == 'p' || cInput[0] == 'q' ||
cInput[0] == 's' || cInput[0] == 't' || cInput[0] == 'v' ||
cInput[0] == 'x' || cInput[0] == 'z')
{
++iNumConsonants;
}
else
{
++iNumOther;
}
} while (strcmp(cInput, "q"));
--iNumConsonants; // q - at the end detected as word(consonant)
cout << iNumVowels << " words beginning with vowels\n";
cout << iNumConsonants << " words beginning with consonants\n";
cout << iNumOther << " others\n";
return 0;
}
// Different method - pseudocode
/*
char sConsonants[]{'b', 'c', 'd', 'f', 'g', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 's', 't', 'v', 'x', 'z',
'B', 'C', 'D', 'F', 'G', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'S', 'T', 'V', 'X', 'Z'};
char sWovels[]{'a', 'e', 'i', 'o', 'u',
'A', 'E', 'I', 'O', 'U'};
cin >> cInput;
if (!isalpha(cInput[0]))
{
++iNumOther;
}
else{
for (size_t i = 0; i < 12; i++)
{
if(cInput[0] == sConsonants[i] || cInput[0] == sConsonants[i+11] || cInput[0] == sConsonants[i + 22]){
++iNumConsonants;
break;
}
else (cInput[0] == sWovels[i]){
++iNumVowels;
break;
}
}
}
*/
8 - Write a program that opens a text file, reads it character-by-character to the end of the file, and reports the number of characters in the file.
Code
#include <iostream>
#include <fstream>
#include <cstdlib>
int main()
{
using namespace std;
int iDataCounter;
ifstream inFile;
inFile.open("./Notes/C++PrimerPlus/exercises/chapter6/ch6_8.txt"); //OR ./ch6_8.txt
if (!inFile.is_open())
{
cout << "Could not open the file" << endl;
cout << "Program terminating.\n";
}
while(inFile.good()){
++iDataCounter;
char temp;
inFile >> temp;
}
cout << "\nnumber of characters in the file " << iDataCounter << endl;
inFile.close();
return 0;
}
9 - Do Programming Exercise 6 but modify it to get information from a file. The first item in the file should be the number of contributors, and the rest of the file should consist of pairs of lines, with the first line of each pair being a contributor’s name and the second line being a contribution. That is, the file should look like this:
Code
#include <iostream>
#include <string>
#include <fstream>
struct stSocietyPRI
{
std::string name;
double contribution;
};
int main()
{
using namespace std;
int iContrbutors{}, iCounter{};
ifstream inFile;
inFile.open("./Notes/C++PrimerPlus/exercises/chapter6/ch6_9.txt");
if (!inFile.is_open()) // failed to open file
{
cout << "Could not open the file" << endl;
cout << "Terminate program.\n";
exit(EXIT_FAILURE);
}
if(inFile.good()){
inFile >> iContrbutors; // First line
}
stSocietyPRI *pSociety = new stSocietyPRI[iContrbutors];
// Read contributors from file
for (size_t i = 0; i < iContrbutors; i++)
{
inFile.get(); // clear buffer
getline(inFile, pSociety[i].name);
inFile >> pSociety[i].contribution;
}
// Print Grand Patrons
iCounter = 0;
cout << "Grand Patrons: \n";
for (size_t i = 0; i < iContrbutors; i++)
{
if (pSociety[i].contribution >= 10000)
{
cout << "\t" << pSociety[i].name << "; \n";
++iCounter;
}
}
if (iCounter == 0)
cout << "\tnone\n";
// Print the rest Patrons
iCounter = 0;
cout << "Patrons: \n";
for (size_t i = 0; i < iContrbutors; i++)
{ if (pSociety[i].contribution < 10000)
{
cout << "\t" << pSociety[i].name << "; \n";
++iCounter;
}
}
if (iCounter == 0)
cout << "\tnone\n";
return 0;
}
Chapter 7
1 -
Write a program that repeatedly asks the user to enter pairs of numbers until at least one of the pair is 0.
For each pair, the program should use a function to calculate the harmonic mean of the numbers.
The function should return the answer to main(), which should report the result. The harmonic mean of the
numbers is the inverse of the average of the inverses and can be calculated as follows:
\(\(HarmonicMean = 2.0 × x × y / (x + y)\)\)
Code
#include <iostream>
double fnHarmonicMean(double dNumX, double dNumY)
{
return (2 * dNumX * dNumY) / (dNumX + dNumY);
}
int main()
{
using namespace std;
double dHarmonicMean{1};
double dNum[2]{};
cout << "\nCalculate harmonic mean of pair of numbers.";
cout << "\nFor one of input equal '0', program terminate.";
do
{
cout << "\nEnter two noumbers after space: ";
if (!(cin >> dNum[0] >> dNum[1]))
{
cin.clear();
while (cin.get() != '\n')
continue;
cout << "\nTry again.\n";
continue;
}
dHarmonicMean = fnHarmonicMean(dNum[0], dNum[1]);
if (!dHarmonicMean)
break;
cout << "\nHarmonic mean: " << dHarmonicMean;
cin.clear();
} while (dHarmonicMean != 0);
cout << "\n\n\tBye! Bye! :)\n";
return 0;
}
2 - Write a program that asks the user to enter up to 10 golf scores, which are to be stored in an array.You should provide a means for the user to terminate input prior to entering 10 scores.The program should display all the scores on one line and report the average score. Handle input, display, and the average calculation with three separate array-processing functions
Code
#include <iostream>
using namespace std;
int fnInput(double *pdScores, int iLength);
// int fnInput(double pdScores[], int iLength); // The same
double fnCalculation(double *pdScores, int iNumEl);
void fnDisplay(double *dFnScores, double dFnAverage, int iNumEl);
int main(){
const int iArrayLength{10};
double dScores[iArrayLength]{};
double dAverage{};
int iNumEl{};
iNumEl = fnInput(dScores, iArrayLength);
dAverage = fnCalculation(dScores, iNumEl);
fnDisplay(dScores, dAverage, iNumEl);
return 0;
}
int fnInput(double *dFnScores, int iLength){
cout << "\nEnter 10 golf scores (`q` to quit):\n#1 Score: ";
int i{};
while(cin >> dFnScores[i] && i < iLength-1)
cout << "#" << (++i + 1) << " Score: ";
return i;
}
double fnCalculation(double *dFnScores, int iNumEl){
double dFnAverage{};
for (int i{}; i <= iNumEl; ++i){
cout << "\t" << dFnAverage << " " << dFnScores[i];
dFnAverage += dFnScores[i];
}
dFnAverage = dFnAverage / (iNumEl + 1);
return dFnAverage;
}
void fnDisplay(double *dFnScores, double dFnAverage, int iNumEl){
cout << "\nScores: ";
for (int j{}; j <= iNumEl; ++j)
cout << dFnScores[j] << ", ";
cout << "\nAverage: " << dFnAverage << endl;
}
3 - Here is a structure declaration:
- Write a function that passes a
boxstructure by value and that displays the value of each member. - Write a function that passes the address of a
boxstructure and that sets thevolumemember to the product of the other three dimensions. - Write a simple program that uses these two functions.
Code
#include <iostream>
#include <string.h>
using namespace std;
struct box
{
char maker[40];
float height;
float width;
float length;
float volume;
};
void fnBoxVal(box b1);
void fnBoxAddr(box *b2);
int main(){
box sBox1;
box * sBox2 = new box;
// sBox1 - value
strcpy(sBox1.maker, "Oh No!");
sBox1.height = 123.3;
sBox1.width = 34;
sBox1.length = 899;
sBox1.volume = 500;
fnBoxVal(sBox1);
fnBoxAddr(&sBox1);
// sBox2 - pointer by new
strcpy(sBox2->maker, "Adress Maker");
sBox2->height = 23;
sBox2->width = 45;
sBox2->length = 65;
sBox2->volume = 98;
fnBoxVal(*sBox2);
fnBoxAddr(sBox2);
return 0;
}
void fnBoxVal(box b1){
cout << "maker: " << b1.maker << endl;
cout << "height: " << b1.height << endl;
cout << "width: " << b1.width << endl;
cout << "length: " << b1.length << endl;
cout << "volume: " << b1.volume << endl << endl;
}
void fnBoxAddr(box *b2){
b2->height = b2->volume;
b2->width = b2->volume;
b2->length = b2->volume;
cout << "maker: " << b2->maker << endl;
cout << "height: " << b2->height << endl;
cout << "width: " << b2->width << endl;
cout << "length: " << b2->length << endl;
cout << "volume: " << b2->volume << endl << endl;
}
4 - Many state lotteries use a variation of the simple lottery portrayed by Listing 7.4 (lotto). In these variations you choose several numbers from one set and call them the field numbers. For example, you might select five numbers from the field of 1–47).You also pick a single number (called a mega number or a power ball, etc.) from a second range, such as 1–27. To win the grand prize, you have to guess all the picks correctly. The chance of winning is the product of the probability of picking all the field numbers times the probability of picking the mega number. For instance, the probability of winning the example described here is the product of the probability of picking 5 out of 47 correctly times the probability of picking 1 out of 27 correctly. Modify Listing 7.4 to calculate the probability of winning this kind of lottery.
Code
#include <iostream>
// Note: some implementations require double instead of long double
long double probability(unsigned numbers, unsigned picks);
int main()
{
using namespace std;
double total, choices, totalMega;
cout << "Enter the total number of choices on the game card, total number of choices on mega number\n"
"and the number of picks allowed :\n";
while ((cin >> total >> totalMega >> choices) && choices <= total)
{
double temp = probability(total, choices);
cout << "You have one chance in ";
cout << temp;
temp = temp * (probability(totalMega, 1));
cout << " of winning in game card.\n";
cout << "and one chance in: " << temp << " of winning mega number" << endl;
cout << "Next two numbers (q to quit): ";
}
cout << "bye\n";
return 0;
}
// the following function calculates the probability of picking picks
// numbers correctly from numbers choices
long double probability(unsigned numbers, unsigned picks)
{
long double result = 1.0; // here come some local variables
long double n;
unsigned p;
for (n = numbers, p = picks; p > 0; n--, p--)
result = result * n / p;
return result;
}
// R = (51 × 50 × 49 × 48 × 47 × 46) / (6 × 5 × 4 × 3 × 2 × 1)
5 - Define a recursive function that takes an integer argument and returns the factorial of that argument. Recall that 3 factorial, written 3!, equals 3 × 2!, and so on, with 0! defined as 1. In general, if n is greater than zero, n! = n * (n - 1)!.Test your function in a program that uses a loop to allow the user to enter various values for which the program reports the factorial
Code
#include <iostream>
using namespace std;
double fnFactorial(int iFactor);
int main(){
int iFactor{};
double dFactorial{};
cout << "\nEnter a number to get factorial: ";
while (!(cin >> iFactor))
{
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
dFactorial = fnFactorial(iFactor);
cout << "\nFactorial: " << dFactorial << endl;
return 0;
}
double fnFactorial(int iFactor){
if(iFactor - 1 > 0)
return iFactor * fnFactorial(--iFactor);
return 1;
}
6 - Write a program that uses the following functions:
Fill_array() takes as arguments the name of an array of double values and an
array size. It prompts the user to enter double values to be entered in the array. It
ceases taking input when the array is full or when the user enters non-numeric
input, and it returns the actual number of entries.
Show_array() takes as arguments the name of an array of double values and an
array size and displays the contents of the array.
Reverse_array() takes as arguments the name of an array of double values and an
array size and reverses the order of the values stored in the array.
The program should use these functions to fill an array, show the array, reverse the
array, show the array, reverse all but the first and last elements of the array, and then
show the array.
Code
#include <iostream>
int Fill_array(double *arr, int arrSize);
void Show_array(double *arr, int arrSize);
void Reverse_array(double *arr, int arrSize);
int main(){
int iArrSize {10};
double *dArray = new double[iArrSize];
iArrSize = Fill_array(dArray, iArrSize);
std::cout << "\n" << iArrSize << "\n";
Show_array(dArray, iArrSize);
Reverse_array(dArray, iArrSize);
Show_array(dArray, iArrSize);
Reverse_array(dArray + 1, iArrSize - 2);
Show_array(dArray, iArrSize);
}
int Fill_array(double *arr, int arrSize){
int i {};
std::cout << "\nEnter value of: \n";
while(i < arrSize)
{
std::cout << "#" << i + 1 << " element: ";
// arr[i] = i; // Autofill : )
while (!(std::cin >> arr[i]))
{
std::cout << "Not a number. Breaking function!";
std::cin.clear();
while(std::cin.get() != '\n')
continue;
return i;
}
++i;
}
return i;
}
void Show_array(double *arr, int arrSize){
std::cout << std::endl;
for (int i {0}; i < arrSize; ++i)
std::cout << arr[i] << ", ";
}
void Reverse_array(double *arr, int arrSize){
for (int i {}, j {arrSize - 1}; i < arrSize / 2; ++i, --j)
{
double temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
7 -
Redo Listing 7.7 (arrfun3), modifying the three array-handling functions to each use two
pointer parameters to represent a range. The fill_array() function, instead of
returning the actual number of items read, should return a pointer to the location
after the last location filled; the other functions can use this pointer as the second
argument to identify the end of the data.
Code
// arrfun3.cpp -- array functions and const
#include <iostream>
const int Max = 5;
// function prototypes
double * fill_array(double ar[], const int *limit);
void show_array(const double ar[], double *n); // don't change data
void revalue(double r, double ar[], double *n);
int main()
{
using namespace std;
double properties[Max];
double *size = fill_array(properties, &Max);
show_array(properties, size);
if (*size > 0)
{
cout << "Enter revaluation factor: ";
double factor;
while (!(cin >> factor)) // bad input
{
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Bad input; Please enter a number: ";
}
revalue(factor, properties, size);
show_array(properties, size);
}
cout << "Done.\n";
cin.get();
cin.get();
return 0;
}
double * fill_array(double ar[], const int *limit)
{
using namespace std;
double temp;
int i;
for (i = 0; i < *limit; i++)
{
cout << "Enter value #" << (i + 1) << ": ";
cin >> temp;
if (!cin) // bad input
{
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Bad input; input process terminated.\n";
break;
}
else if (temp < 0) // signal to terminate
break;
ar[i] = temp;
}
return &ar[i];
}
// the following function can use, but not alter,
// the array whose address is ar
void show_array(const double ar[], double *n)
{
using namespace std;
for (int i = 0; ar[i] != *n; i++)
{
cout << "Property #" << (i + 1) << ": $";
cout << ar[i] << endl;
}
}
// multiplies each element of ar[] by r
void revalue(double r, double ar[], double *n)
{
for (int i = 0; ar[i] != *n; i++)
ar[i] *= r;
}
8 - Redo Listing 7.15 (arrobj) without using the array class. Do two versions:
a. Use an ordinary array of const char * for the strings representing the season
names, and use an ordinary array of double for the expenses.
b. Use an ordinary array of const char * for the strings representing the season
names, and use a structure whose sole member is an ordinary array of
double for the expenses. (This design is similar to the basic design of the
array class.)
Code
/// A version /// -----------
/*
#include <iostream>
#include <string>
// constant data
const int Seasons = 4;
const char Snames[Seasons][10] =
{"Spring", "Summer", "Fall", "Winter"};
// function to modify array object
void fill(double t.expenses[],const int Seasons);
// function that uses array object without modifying it
void show(double t.expenses[],const int Seasons);
int main()
{
double expenses[Seasons]{};
fill(expenses, Seasons);
show(expenses, Seasons);
return 0;
}
void fill(double t.expenses[],const int Seasons)
{
using namespace std;
for (int i = 0; i < Seasons; i++)
{
cout << "Enter " << Snames[i] << " expenses: ";
cin >> t.expenses[i];
}
}
void show(double t.expenses[],const int Seasons)
{
using namespace std;
double total = 0.0;
cout << "\nEXPENSES\n";
for (int i = 0; i < Seasons; i++)
{
cout << Snames[i] << ": $" << t.expenses[i] << endl;
total += t.expenses[i];
}
cout << "Total Expenses: $" << total << endl;
}
*/
/// B version /// -----------
#include <iostream>
#include <string>
// constant data
const int Seasons = 4;
const char Snames[Seasons][10] =
{"Spring", "Summer", "Fall", "Winter"};
struct sAll{
double expenses[Seasons]{};
};
// function to modify array object
void fill(sAll *t,const int Seasons);
// function that uses array object without modifying it
void show(sAll *t,const int Seasons);
int main()
{
sAll exp;
fill(&exp, Seasons);
show(&exp, Seasons);
return 0;
}
void fill(sAll *t,const int Seasons)
{
using namespace std;
for (int i = 0; i < Seasons; i++)
{
cout << "Enter " << Snames[i] << " expenses: ";
cin >> t->expenses[i];
}
}
void show(sAll *t,const int Seasons)
{
using namespace std;
double total = 0.0;
cout << "\nEXPENSES\n";
for (int i = 0; i < Seasons; i++)
{
cout << Snames[i] << ": $" << t->expenses[i] << endl;
total += t->expenses[i];
}
cout << "Total Expenses: $" << total << endl;
}
/*
Enter Spring expenses: 212
Enter Summer expenses: 256
Enter Fall expenses: 208
Enter Winter expenses: 244
EXPENSES
Spring: $212
Summer: $256
Fall: $208
Winter: $244
Total: $920
*/
9 - This exercise provides practice in writing functions dealing with arrays and structures. The following is a program skeleton. Complete it by providing the described functions:
#include <iostream>
using namespace std;
const int SLEN = 30;
struct student
{
char fullname[SLEN];
char hobby[SLEN];
int ooplevel;
};
// getinfo() has two arguments: a pointer to the first element of
// an array of student structures and an int representing the
// number of elements of the array. The function solicits and
// stores data about students. It terminates input upon filling
// the array or upon encountering a blank line for the student
// name. The function returns the actual number of array elements
// filled.
int getinfo(student pa[], int n);
// display1() takes a student structure as an argument
// and displays its contents
void display1(student st);
// display2() takes the address of student structure as an
// argument and displays the structure’s contents
void display2(const student *ps);
// display3() takes the address of the first element of an array
// of student structures and the number of array elements as
// arguments and displays the contents of the structures
void display3(const student pa[], int n);
int main()
{
cout << "Enter class size : ";
int class_size;
cin >> class_size;
while (cin.get() != '\n')
continue;
student *ptr_stu = new student[class_size];
int entered = getinfo(ptr_stu, class_size);
for (int i = 0; i < entered; i++)
{
display1(ptr_stu[i]);
display2(&ptr_stu[i]);
}
display3(ptr_stu, entered);
delete[] ptr_stu;
cout << "Done\n";
return 0;
}
Code
#include <iostream>
using namespace std;
const int SLEN = 30;
struct student
{
char fullname[SLEN];
char hobby[SLEN];
int ooplevel;
};
// getinfo() has two arguments: a pointer to the first element of
// an array of student structures and an int representing the
// number of elements of the array. The function solicits and
// stores data about students. It terminates input upon filling
// the array or upon encountering a blank line for the student
// name. The function returns the actual number of array elements
// filled.
int getinfo(student pa[], int n);
// display1() takes a student structure as an argument
// and displays its contents
void display1(student st);
// display2() takes the address of student structure as an
// argument and displays the structure’s contents
void display2(const student *ps);
// display3() takes the address of the first element of an array
// of student structures and the number of array elements as
// arguments and displays the contents of the structures
void display3(const student pa[], int n);
int main()
{
cout << "Enter class size : ";
int class_size;
cin >> class_size;
while (cin.get() != '\n')
continue;
student *ptr_stu = new student[class_size];
int entered = getinfo(ptr_stu, class_size);
cout << "Sadf sadf " << entered << endl;
for (int i = 0; i < entered; i++)
{
display1(ptr_stu[i]);
display2(&ptr_stu[i]);
}
display3(ptr_stu, entered);
delete[] ptr_stu;
cout << "Done\n";
return 0;
}
int getinfo(student pa[], int n)
{
int i{};
do
{
cout << "\nEnter the name of " << i + 1 << " student: ";
while (!(cin.get(pa[i].fullname, SLEN))) // the only function that reads an empty line and sets failbit
return i;
cout << "Enter the hobby of " << i + 1 << " student: ";
cin.get();
while (!(cin.get(pa[i].hobby, SLEN)))
{
cin.clear();
while (cin.get() != '\n')
break;
break;
}
cout << "Enter the oop level of " << i + 1 << " student: ";
while (!(cin >> pa[i].ooplevel))
{
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Bad input; Please enter a number: ";
}
// read newlines (in other case you will only read one line,
// the rest will fill from buffer - chapter 6: Review, 9)
while (cin.get() != '\n')
continue;
} while (++i < n);
return i;
}
void display1(student st)
{
cout << "\n\t<display1>";
cout << "\nName: " << st.fullname;
cout << "\nHobby: " << st.hobby;
cout << "\nOOP level: " << st.ooplevel << endl;
}
void display2(const student *ps)
{
cout << "\n\t<display2>";
cout << "\nName: " << ps->fullname;
cout << "\nHobby: " << ps->hobby;
cout << "\nOOP level: " << ps->ooplevel << endl;
}
void display3(const student pa[], int n)
{
cout << "\n\t<display3>";
for (int i{}; i < n; ++i)
{
cout << "\nName: " << (pa + i)->fullname;
cout << "\nHobby: " << (pa + i)->hobby;
cout << "\nOOP level: " << (pa + i)->ooplevel << endl;
}
}
10 -
Design a function calculate() that takes two type double values and a pointer to
a function that takes two double arguments and returns a double.The
calculate() function should also be type double, and it should return the value
that the pointed-to function calculates, using the double arguments to
calculate(). For example, suppose you have this definition for the add()
function:
Then, the function call in the following would cause calculate() to pass the values
2.5 and 10.4 to the add() function and then return the add() return value
(12.9):
Use these functions and at least one additional function in the add() mold in a
program.The program should use a loop that allows the user to enter pairs of numbers.
For each pair, use calculate() to invoke add() and at least one other function.
If you are feeling adventurous, try creating an array of pointers to add()-style
functions and use a loop to successively apply calculate() to a series of functions
by using these pointers. Hint: Here’s how to declare such an array of three pointers:
You can initialize such an array by using the usual array initialization syntax and function names as addresses.
Code
#include <iostream>
double add(double, double);
double calculate(double, double, double (*add)(double, double));
int main()
{
double a{};
double b{};
/// A version /// -----------
/*
std::cout << "\nAdd pairs of numbers.\nEnter 2 numbers after space, q to quit:\n";
while (std::cin >> a >> b)
{
if (!std::cin)
break;
std::cout << "\nAdded: " << a << " + " << b
<< " = " << calculate(a, b, add);
std::cout << "\n\nEnter 2 new numbers: ";
// Clear buffer if more numbers than 2
std::cin.clear();
while (std::cin.get() != '\n')
continue;
}
std::cout << "\n\tBye Bye!";
*/
/// B version /// -----------:
// // try creating an array of pointers to add()-style
// // functions and use a loop to successively apply calculate() to a series of functions
// // by using these pointers.
double (*pf[3])(double, double){add, add, add};
std::cout << "\nAdd pairs of numbers.\nEnter 2 numbers after space, q to quit:\n";
while (std::cin >> a >> b)
{
if (!std::cin)
break;
double temp1 = calculate(a, b, pf[0]);
double temp2 = calculate(temp1, a, pf[1]);
double temp3 = calculate(temp2, temp1, pf[2]);
std::cout << "\nAdded: " << a << " + " << b
<< " = " << temp1;
std::cout << "\nAdded: " << temp1 << " + " << a
<< " = " << temp2;
std::cout << "\nAdded: " << temp2 << " + " << temp1
<< " = " << temp3;
std::cout << "\n\nEnter 2 new numbers: ";
// Clear buffer if more numbers than 2
std::cin.clear();
while (std::cin.get() != '\n')
continue;
}
std::cout << "\n\tBye Bye!";
}
double add(double x, double y)
{
return x + y;
}
double calculate(double a, double b, double (*add)(double, double))
{
return add(a, b);
}
Chapter 8
1 - Write a function that normally takes one argument, the address of a string, and prints that string once. However, if a second, type int, argument is provided and is nonzero, the function should print the string a number of times equal to the number of times that function has been called at that point. (Note that the number of times the string is printed is not equal to the value of the second argument; it is equal to the number of times the function has been called.) Yes, this is a silly function, but it makes you use some of the techniques discussed in this chapter. Use the function in a simple program that demonstrates how the function works.
Code
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
static int iNum{};
void fnFun(string *cStr, int iPrint = 1);
void fnFun(char *cStr, int iPrint = 1);
int main()
{
char *cSthChar = new char[50];
string *cSthString = new string;
int iSth{};
char cChoice{};
cout << "\nWrite words to call finction and print it";
cout << "\nthe number of times function was called";
cout << "\nWrite 'done' to quit";
cout << "\nType: A - use *std::string, B - use *char[]: ";
cin >> cChoice;
switch (cChoice)
{
case 'A':
do
{
cout << "\nWrite words: ";
cin.getline(cSthChar, 50);
cout << "\nEnter nonzero number to print words: ";
while (!(cin >> iSth))
{
std::cout << "Not a number. Try again: ";
std::cin.clear();
while (std::cin.get() != '\n')
continue;
}
fnFun(cSthChar, iSth);
cin.get();
} while (strcmp(cSthChar, "done"));
delete[] cSthChar;
break;
case 'B':
do
{
cout << "\nWrite words: ";
getline(cin, *cSthString);
cout << "\nEnter nonzero number to print words: ";
while (!(cin >> iSth))
{
std::cout << "Not a number. Try again: ";
std::cin.clear();
while (std::cin.get() != '\n')
continue;
}
fnFun(cSthString, iSth);
cin.get();
} while (!(*cSthString == "done"));
delete[] cSthString;
break;
default:
break;
}
return 0;
}
void fnFun(string *cStr, int iPrint)
{
++iNum;
if (!iPrint)
return;
for (int i{}; i < iNum; i++)
cout << *cStr << endl;
}
void fnFun(char *cStr, int iPrint)
{
++iNum;
if (!iPrint)
return;
for (int i{}; i < iNum; ++i)
cout << cStr << endl;
}
2 -
The CandyBar structure contains three members.The first member holds the brand
name of a candy bar.The second member holds the weight (which may have a fractional
part) of the candy bar, and the third member holds the number of calories
(an integer value) in the candy bar.Write a program that uses a function that takes
as arguments a reference to CandyBar, a pointer-to-char, a double, and an int and
uses the last three values to set the corresponding members of the structure. The last
three arguments should have default values of “Millennium Munch,” 2.85, and 350.
Also the program should use a function that takes a reference to a CandyBar as an
argument and displays the contents of the structure. Use const where appropriate.
Code
#include <iostream>
#include <cstring>
struct CandyBar{
char name[50];
float weight;
int calories;
};
void fnFunA(CandyBar &cb, const char *cstr, int num){
--num; // 9 letters
cb.name[0] = cstr[num-1];
cb.weight = float(cstr[num-2]) * 0.1;
cb.calories = int(cstr[num-3]);
}
void fnFunB(CandyBar const &cb){
std::cout << cb.name << ", ";
std::cout << cb.weight << ", ";
std::cout << cb.calories << std::endl;
}
int main(){
int iNum {10};
char cData[iNum] {"qwertyuiO"};
CandyBar myCandy {"Millennium Munch", 2.85, 350};
std::cout << "\nCurrent data: \n";
fnFunB(myCandy);
std::cout << "\n-PROCESS DATA-\n";
fnFunA(myCandy, cData, iNum);
std::cout << "\nNew data: \n";
fnFunB(myCandy);
std::cout << std::endl;
return 0;
}
3 -
Write a function that takes a reference to a string object as its parameter and that
converts the contents of the string to uppercase. Use the toupper() function
described in Table 6.4 of Chapter 6.Write a program that uses a loop which allows
you to test the function with different input.A sample run might look like this:
Enter a string (q to quit): go away
GO AWAY
Next string (q to quit): good grief!
GOOD GRIEF!
Next string (q to quit): q
Bye.
Code
#include <iostream>
#include <string>
#include <cctype>
void fnFunA(std::string &data){
int iLet {sizeof(data)/sizeof(data[0])};
char temp[iLet];
for (int i {}; i < iLet; ++i)
data[i] = toupper((int)data[i]);
}
int main(){
std::string sData;
std::cout << "\nEnter a string (q to quit): ";
while (std::getline(std::cin, sData))
{
if (sData == "q")
break;
fnFunA(sData);
std::cout << sData << "\n";
std::cout << "Next string (q to quit): ";
}
return 0;
}
4 - The following is a program skeleton:
#include <iostream>
using namespace std;
#include <cstring> // for strlen(), strcpy()
struct stringy
{
char *str; // points to a string
int ct; // length of string (not counting '\0')
};
// prototypes for set(), show(), and show() go here
int main()
{
stringy beany;
char testing[] = "Reality isn't what it used to be.";
set(beany, testing); // first argument is a reference,
// allocates space to hold copy of testing,
// sets str member of beany to point to the
// new block, copies testing to new block,
// and sets ct member of beany
show(beany); // prints member string once
show(beany, 2); // prints member string twice
testing[0] = 'D';
testing[1] = 'u';
show(testing); // prints testing string once
show(testing, 3); // prints testing string thrice
show("Done!");
return 0;
}
Complete this skeleton by providing the described functions and prototypes. Note
that there should be two show() functions, each using default arguments. Use
const arguments when appropriate. Note that set() should use new to allocate
sufficient space to hold the designated string.The techniques used here are similar
to those used in designing and implementing classes. (You might have to alter the
header filenames and delete the using directive, depending on your compiler.)
Code
#include <iostream>
#include <cstring> // for strlen(), strcpy()
using namespace std;
struct stringy
{
char *str; // points to a string
int ct; // length of string (not counting '\0')
};
// prototypes for set(), show(), and show() go here
void show(stringy const &sStringy, int iNum = 1);
void show(const char *cWord, int iNum = 1);
void set(stringy &sStringy, const char *cString);
int main()
{
stringy beany;
char testing[] = "Reality isn't what it used to be.";
set(beany, testing); // first argument is a reference,
// allocates space to hold copy of testing,
// sets str member of beany to point to the
// new block, copies testing to new block,
// and sets ct member of beany
show(beany); // prints member string once
show(beany, 2); // prints member string twice
testing[0] = 'D';
testing[1] = 'u';
show(testing); // prints testing string once
show(testing, 3); // prints testing string thrice
show("Done!");
return 0;
}
void set(stringy &sStringy, const char *cString){
const int iLength = strlen(cString);
static char * cTemp = new char[iLength + 1];
strcpy(cTemp, cString);
sStringy.str = cTemp;
sStringy.ct = iLength;
// cout << endl << "sStringy str :" << sStringy.str << ", in memory: " << &sStringy.str;
// cout << endl << "cString :" << cString << ", in memory: " << &cString;
// cout << endl << "cTemp :" << cTemp << ", in memory: " << &cTemp;
}
void show(stringy const &sStringy, int iNum){
for (int i {}; i < iNum; ++i)
cout << endl << sStringy.str;
}
void show(const char *cWord, int iNum){
for (int i {}; i < iNum; ++i)
cout << endl << cWord;
}
5 -
Write a template function max5() that takes as its argument an array of five items
of type T and returns the largest item in the array. (Because the size is fixed, it can
be hard-coded into the loop instead of being passed as an argument.) Test it in a
program that uses the function with an array of five int value and an array of five
double values.
Code
#include <iostream>
template <typename T>
T max5(T tVal[5]);
int main()
{
int iTestVal[5] {9,3,6,8,4};
double dTestVal[5] {9.35, 9.424, 9.383, 9.123, 9.13};
double dOutput {};
std::cout << "\n int test: \n";
dOutput = max5(iTestVal);
std::cout << dOutput << ", and fun : " << max5(iTestVal) << std::endl;
std::cout << "\n double test: \n";
dOutput = max5(dTestVal);
std::cout << dOutput << ", and fun : " << max5(dTestVal) << std::endl ;
std::cout << std::endl;
return 0;
}
template<typename T>
T max5(T tVal[5])
{
T tMax {tVal[0]};
for (int i {1}; i < 5; i++)
if (tMax < tVal[i])
tMax = tVal[i];
return tMax;
}
6 -
Write a template function maxn() that takes as its arguments an array of items of
type T and an integer representing the number of elements in the array and that
returns the largest item in the array.Test it in a program that uses the function template
with an array of six int value and an array of four double values.The program
should also include a specialization that takes an array of pointers-to-char as
an argument and the number of pointers as a second argument and that returns the
address of the longest string. If multiple strings are tied for having the longest
length, the function should return the address of the first one tied for longest.Test
the specialization with an array of five string pointers.
Code
#include <iostream>
#include <cstring>
template <typename T>
T maxn(T tVal[], int iNumEl);
template <> const char *maxn(const char *cArr[], int iNumPtr);
int main()
{
int iVals[6] {123, 234, 564, 34, 535, 543};
double dVals[4] {1.23, 2.34, 5.64, 3.4};
const char *cVals[6] {"fdsffds", "lubie placki", "was is das", "i like pancakes", "ni hao", "arigato"};
std::cout << "\n int test: \n";
std::cout << maxn(iVals, 6);
std::cout << "\n double test: \n";
std::cout << maxn(dVals, 4);
std::cout << "\n c-string test: \n";
std::cout << maxn(cVals, 6);
std::cout << std::endl << "str2 :" << *cVals << ", in memory: " << cVals;
return 0;
}
template <typename T>
T maxn(T tVal[], int iNumEl)
{
T tMax{tVal[0]};
for (int i{}; i < iNumEl; ++i)
if (tMax < tVal[i])
tMax = tVal[i];
return tMax;
}
template <> const char *maxn(const char *cArr[], int iNumPtr){
int iMax = strlen(cArr[0]);
int tmp{};
for (int i{}; i < iNumPtr; ++i){
if (iMax < strlen(cArr[i])){
iMax = strlen(cArr[i]);
tmp = i;
}
}
std::cout << std::endl << "str1 :" << *cArr << ", in memory: " << cArr << std::endl;
return cArr[tmp];
}
7 -
Modify Listing 8.14 (tempover) so that it uses two template functions called SumArray() to
return the sum of the array contents instead of displaying the contents.The program
now should report the total number of things and the sum of all the debts
Code
#include <iostream>
template <typename T> // template A
T SumArray(T arr[], int n);
template <typename T> // template B
T SumArray(T *arr[], int n);
struct debts
{
char name[50];
double amount;
};
int main()
{
using namespace std;
int things[6] = {13, 31, 103, 301, 310, 130};
struct debts mr_E[3] =
{
{"Ima Wolfe", 2400.0},
{"Ura Foxe", 1300.0},
{"Iby Stout", 1800.0}};
double *pd[3];
// set pointers to the amount members of the structures in mr_E
for (int i = 0; i < 3; i++)
pd[i] = &mr_E[i].amount;
cout << "Listing Mr. E's counts of things:\n";
// things is an array of int
cout << SumArray(things, 6) << endl << endl; // uses template A
cout << "Listing Mr. E's debts:\n";
// pd is an array of pointers to double
cout << SumArray(pd, 3) << endl << endl; // uses template B (more specialized)
return 0;
}
template <typename T>
T SumArray(T arr[], int n)
{
using namespace std;
T tSum{};
cout << "template A\n";
for (int i = 0; i < n; i++)
tSum += arr[i];
return tSum;
}
template <typename T>
T SumArray(T *arr[], int n)
{
using namespace std;
T tSum{};
cout << "template B\n";
for (int i = 0; i < n; i++)
tSum += *arr[i];
return tSum;
}
Chapter 9
1 - Here is a header file:
// golf.h -- for pe9-1.cpp
const int Len = 40;
struct golf
{
char fullname[Len];
int handicap;
};
// non-interactive version:
// function sets golf structure to provided name, handicap
// using values passed as arguments to the function
void setgolf(golf & g, const char * name, int hc);
// interactive version:
// function solicits name and handicap from user
// and sets the members of g to the values entered
// returns 1 if name is entered, 0 if name is empty string
int setgolf(golf & g);
// function resets handicap to new value
void handicap(golf & g, int hc);
// function displays contents of golf structure
void showgolf(const golf & g);
Note that setgolf() is overloaded. Using the first version of setgolf() would look like this:
The function call provides the information that’s stored in the ann structure. Using the second version of setgolf() would look like this:
The function would prompt the user to enter the name and handicap and store
them in the andy structure. This function could (but doesn’t need to) use the first
version internally.
Put together a multifile program based on this header. One file, named golf.cpp,
should provide suitable function definitions to match the prototypes in the header
file. A second file should contain main() and demonstrate all the features of the
prototyped functions. For example, a loop should solicit input for an array of golf
structures and terminate when the array is full or the user enters an empty string
for the golfer’s name. The main() function should use only the prototyped functions
to access the golf structures.
(compile: g++ ch9_1_golf.cpp ch9_1_main.cpp)
Code - Prototypes
#include <iostream>
#include "ch9_1_golf.h"
void setgolf(golf &g, const char *name, int hc)
{
strcpy(g.fullname, name);
g.handicap = hc;
}
int setgolf(golf &g)
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "\nEnter the name: ";
// std::cin >> g.fullname;
std::cin.getline(g.fullname, Len) ;
std::cout << "Enter the handicap: ";
// std::cin >> g.handicap;
while (!(std::cin >> g.handicap))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a number: ";
}
// std::cin.get(); // clear the input buffer
if (g.fullname == "")
{
return 0;
}
return 1;
}
void handicap(golf &g, int hc)
{
g.handicap = hc;
}
void showgolf(const golf &g)
{
std::cout << "\t" << g.fullname << "\t\t";
std::cout << g.handicap << std::endl;
}
Code - headers
#include <iostream>
#include <cstring>
const int Len = 40;
struct golf
{
char fullname[Len];
int handicap;
};
// non-interactive version:
// function sets golf structure to provided name, handicap
// using values passed as arguments to the function
void setgolf(golf &g, const char *name, int hc);
// interactive version:
// function solicits name and handicap from user
// and sets the members of g to the values entered
// returns 1 if name is entered, 0 if name is empty string
int setgolf(golf &g);
// function resets handicap to new value
void handicap(golf &g, int hc);
// function displays contents of golf structure
void showgolf(const golf &g);
Code - Program
#include <iostream>
#include "ch9_1_golf.h"
void fnPrintMenu()
{
std::cout
<< "\nPlease select:\n"
<< "\ta) non-interactive version\tb) interactive version\n"
<< "\tc) print all players\t\td) change number of players\n"
<< "\te) quit" << std::endl;
}
int main()
{
char strFullname[40];
int iHandicap{}, iPlayers{1};
char cMenu;
do
{
std::cout << "\nEnter the number of players (default is 1, max is 40): ";
std::cin >> iPlayers;
if (iPlayers > 40 || iPlayers < 1)
{
std::cout << "Invalid number of players, try again\n";
}
} while (iPlayers > 40 || iPlayers < 1);
fnPrintMenu();
std::cin >> cMenu;
// golf *andy = new golf[iPlayers]; // dynamic memory allocation [1/2]
golf andy[iPlayers]; // static memory allocation [1/1]
while (true)
{
switch (cMenu)
{
case 'a':
for (int i = 0; i < iPlayers; ++i)
{
// std::cin >> strFullname >> iHandicap;
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cin.getline(strFullname, Len);
while (!(std::cin >> iHandicap))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a number: ";
}
setgolf(andy[i], strFullname, iHandicap);
}
break;
case 'b':
for (size_t i = 0; i < iPlayers; ++i)
{
setgolf(andy[i]);
}
break;
case 'c':
std::cout << "\tName \t\t\tHandicap \n";
std::cout << "\t---------------------------------\n";
for (int i = 0; i < iPlayers; ++i)
{
showgolf(andy[i]);
}
break;
case 'd':
do
{
std::cout << "\nEnter the number of players (default is 1, max is 40): ";
std::cin >> iPlayers;
if (iPlayers > 40 || iPlayers < 1)
{
std::cout << "Invalid number of players, try again\n";
}
} while (iPlayers > 40 || iPlayers < 1);
break;
case 'e':
std::cout << "Bye-bye!\n";
return 0;
default:
std::cout << "Please enter: a, b, c or d: ";
break;
}
fnPrintMenu();
std::cin >> cMenu;
}
// delete [] andy; // dynamic memory allocation [2/2]
return 0;
}
2 -
Redo Listing 9.9 (static.cpp), replacing the character array with a string object. The program
should no longer have to check whether the input string fits, and it can compare
the input string to "" to check for an empty line.
Code
// static.cpp -- using a static local variable
#include <iostream>
#include <string>
// constants
const int ArSize = 10;
// function prototype
void strcount(std::string *str);
int main()
{
using namespace std;
string input;
string *ptrInput = &input;
string next;
cout << "Enter a line:\n";
while (cin)
{
getline(cin, input);
strcount(ptrInput); // can be also `&input`
if (input == "")
break;
cout << "Enter next line (empty line to quit):\n";
}
cout << "\n\n";
strcount(&input);
cout << "Bye\n";
return 0;
}
void strcount(std::string *str)
{
using namespace std;
static int total = 0; // static local variable
int count = 0; // automatic local variable
cout << "\"" << *str << "\" contains ";
count = str->length();
total += count;
cout << count << " characters\n";
cout << total << " characters total\n";
}
3 - Begin with the following structure declaration:
Write a program that uses placement new to place an array of two such structures in a buffer. Then assign values to the structure members (remembering to use strcpy() for the char array) and use a loop to display the contents. Option 1 is to use a static array, like that in:
Listing 9.10:
=== "newplace.cpp"
#include <iostream>
#include <new> // for placement new
const int BUF = 512;
const int N = 5;
char buffer[BUF]; // chunk of memory
int main()
{
using namespace std;
double *pd1, *pd2;
int i;
cout << "Calling new and placement new:\n";
pd1 = new double[N]; // use heap
pd2 = new (buffer) double[N]; // use buffer array
for (i = 0; i < N; i++)
pd2[i] = pd1[i] = 1000 + 20.0 * i;
cout << "Memory addresses:\n"
<< " heap: " << pd1
<< " static: " << (void *)buffer << endl;
cout << "Memory contents:\n";
for (i = 0; i < N; i++)
{
cout << pd1[i] << " at " << &pd1[i] << "; ";
cout << pd2[i] << " at " << &pd2[i] << endl;
}
cout << "\nCalling new and placement new a second time:\n";
double *pd3, *pd4;
pd3 = new double[N]; // find new address
pd4 = new (buffer) double[N]; // overwrite old data
for (i = 0; i < N; i++)
pd4[i] = pd3[i] = 1000 + 40.0 * i;
cout << "Memory contents:\n";
for (i = 0; i < N; i++)
{
cout << pd3[i] << " at " << &pd3[i] << "; ";
cout << pd4[i] << " at " << &pd4[i] << endl;
}
cout << "\nCalling new and placement new a third time:\n";
delete[] pd1;
pd1 = new double[N];
pd2 = new (buffer + N * sizeof(double)) double[N];
for (i = 0; i < N; i++)
pd2[i] = pd1[i] = 1000 + 60.0 * i;
cout << "Memory contents:\n";
for (i = 0; i < N; i++)
{
cout << pd1[i] << " at " << &pd1[i] << "; ";
cout << pd2[i] << " at " << &pd2[i] << endl;
}
delete[] pd1;
delete[] pd3;
return 0;
}
/*
Calling new and placement new:
Memory addresses:
heap: 006E4AB0 static: 00FD9138
Memory contents:
1000 at 006E4AB0; 1000 at 00FD9138
1020 at 006E4AB8; 1020 at 00FD9140
1040 at 006E4AC0; 1040 at 00FD9148
1060 at 006E4AC8; 1060 at 00FD9150
1080 at 006E4AD0; 1080 at 00FD9158
Calling new and placement new a second time:
Memory contents:
1000 at 006E4B68; 1000 at 00FD9138
1040 at 006E4B70; 1040 at 00FD9140
1080 at 006E4B78; 1080 at 00FD9148
1120 at 006E4B80; 1120 at 00FD9150
1160 at 006E4B88; 1160 at 00FD9158
Calling new and placement new a third time:
Memory contents:
1000 at 006E4AB0; 1000 at 00FD9160
1060 at 006E4AB8; 1060 at 00FD9168
1120 at 006E4AC0; 1120 at 00FD9170
1180 at 006E4AC8; 1180 at 00FD9178
1240 at 006E4AD0; 1240 at 00FD9180
*/
, for the buffer. Option 2 is to use regular new to allocate the buffer.
Code
#include <iostream>
struct chaff
{
char dross[20];
int slag;
};
int main(){
// [1] Static array
// [2] New keyword
chaff *myStr = new chaff[2];
for (int i = 0; i < 2; ++i)
{
std::cout << "\nEnter new name for [" << i << "] dross : \t";
std::cin.getline(myStr[i].dross, 20);
std::cout << "Enter new number for [" << i << "] slag : \t";
while (!(std::cin >> myStr[i].slag))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a number: ";
}
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
}
std::cout << "\n";
for (int i = 0; i < 2; ++i)
{
std::cout << "\nName of [" << i << "] dross : " << myStr[i].dross;
std::cout << "; \t\t[" << i << "] slag : " << myStr[i].slag;
}
std::cout << "\n";
delete[] myStr;
return 0;
}
/*
Write a program that uses placement new to place an array of two such structures in
a buffer. Then assign values to the structure members (remembering to use
strcpy() for the char array) and use a loop to display the contents. Option 1 is to
use a static array, like that in Listing 9.10, for the buffer. Option 2 is to use regular
new to allocate the buffer.
*/
4- Write a three-file program based on the following namespace:
namespace SALES
{
const int QUARTERS = 4;
struct Sales
{
double sales[QUARTERS];
double average;
double max;
double min;
};
// copies the lesser of 4 or n items from the array ar
// to the sales member of s and computes and stores the
// average, maximum, and minimum values of the entered items;
// remaining elements of sales, if any, set to 0
void setSales(Sales & s, const double ar[], int n);
// gathers sales for 4 quarters interactively, stores them
// in the sales member of s and computes and stores the
// average, maximum, and minimum values
void setSales(Sales & s);
// display all information in structure s
void showSales(const Sales & s);
}
The first file should be a header file that contains the namespace.The second file should be a source code file that extends the namespace to provide definitions for the three prototyped functions. The third file should declare two Sales objects. It should use the interactive version of setSales() to provide values for one structure and the non-interactive version of setSales() to provide values for the second structure. It should display the contents of both structures by using showSales().
Code - Prototypes
#include <iostream>
#include "ch9_4_sales.h"
// copies the lesser of 4 or n items from the array ar
// to the sales member of s and computes and stores the
// average, maximum, and minimum values of the entered items;
// remaining elements of sales, if any, set to 0
void SALES::setSales(Sales &s, const double ar[], int n)
{
if (n > QUARTERS)
return;
s.average = 0;
s.min = ar[0];
s.max = ar[0];
for (int i = 0; i < n; ++i)
{
if (i < (n - 1))
{
if (s.min > ar[i + 1])
s.min = ar[i + 1];
if (s.max < ar[i + 1])
s.max = ar[i + 1];
}
s.sales[i] += ar[i];
s.average += ar[i];
}
s.average /= n;
}
// gathers sales for 4 quarters interactively, stores them
// in the sales member of s and computes and stores the
// average, maximum, and minimum values
void SALES::setSales(Sales &s)
{
s.average = 0;
s.min = 0;
s.max = 0;
std::cout << "\nSet sales for quarters: ";
for (int i = 0; i < QUARTERS; ++i)
{
std::cout << "\n-> sale " << i << " : ";
while (!(std::cin >> s.sales[i]))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a number: ";
}
}
s.min = s.sales[0];
for (int i = 0; i < QUARTERS; ++i)
{
if (i < (QUARTERS - 1))
{
if (s.min > s.sales[i + 1])
s.min = s.sales[i + 1];
if (s.max < s.sales[i + 1])
s.max = s.sales[i + 1];
}
s.average += s.sales[i];
}
s.average /= QUARTERS;
}
// display all information in structure s
void SALES::showSales(const Sales &s)
{
std::cout << "\n\n";
std::cout << "\t Average: \t" << s.average;
std::cout << "\t Max: \t" << s.max;
std::cout << "\t Min: \t" << s.min << "\n";
for (int i = 0; i < QUARTERS; i++)
std::cout << "\t Sale [" << i << "] : \t" << s.sales[i];
}
Code - headers
#include <iostream>
namespace SALES
{
const int QUARTERS = 4;
struct Sales
{
double sales[QUARTERS];
double average;
double max;
double min;
};
// copies the lesser of 4 or n items from the array ar
// to the sales member of s and computes and stores the
// average, maximum, and minimum values of the entered items;
// remaining elements of sales, if any, set to 0
void setSales(Sales &s, const double ar[], int n);
// gathers sales for 4 quarters interactively, stores them
// in the sales member of s and computes and stores the
// average, maximum, and minimum values
void setSales(Sales &s);
// display all information in structure s
void showSales(const Sales &s);
}
Code - Program
#include <iostream>
#include "ch9_4_sales.h"
using namespace SALES;
void fnPrintMenu()
{
std::cout
<< "\nPlease select:\n"
<< "\ta) non-interactive version\tb) interactive version\n"
<< "\tc) print all sales"
<< "\t\td) quit" << std::endl;
}
int main(){
char cMenu;
Sales *mySales = new Sales[2];
fnPrintMenu();
std::cin >> cMenu;
while (true)
{
switch (cMenu)
{
case 'a':
double temp[QUARTERS];
for (int i = 0; i < QUARTERS; ++i)
{
while (!(std::cin >> temp[i]))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a number: ";
}
}
setSales(mySales[0], temp, QUARTERS);
break;
case 'b':
setSales(mySales[1]);
break;
case 'c':
for (int i = 0; i < 2; ++i)
showSales(mySales[i]);
break;
case 'd':
// break;
// case 'e':
std::cout << "Bye-bye!\n";
return 0;
default:
std::cout << "Please enter: a, b, c or e: ";
break;
}
fnPrintMenu();
std::cin >> cMenu;
}
delete[] mySales;
return 0;
}
/*
The first file should be a header file that contains the namespace.The second file
should be a source code file that extends the namespace to provide definitions for
the three prototyped functions. The third file should declare two Sales objects. It
should use the interactive version of setSales() to provide values for one structure
and the non-interactive version of setSales() to provide values for the second
structure. It should display the contents of both structures by using
showSales().
*/
Chapter 10
1 - Provide method definitions for the class described in Chapter Review Question 5 and write a short program that illustrates all the features.
Code - Prototypes
#ifndef BANK_H_
#define BANK_H_
#include <iostream>
#include <cstring>
class BankAccount
{
private:
std::string name; // or std::string name;
std::string acctnum; // or std::string acctnum;
double balance;
public:
BankAccount(const std::string &client, const std::string &num, double bal = 0.0);
void show(void) const;
void deposit(double cash);
void withdraw(double cash);
};
#endif
Code - Methods
#include "ch10_1.h"
BankAccount::BankAccount(const std::string &client, const std::string &num, double bal)
{
name = client;
acctnum = num;
balance = bal;
}
void BankAccount::show(void) const
{
std::cout << "Name: \t" << name << std::endl;
std::cout << "Account number: \t" << acctnum << std::endl;
std::cout << "Balance: \t" << balance << std::endl << std::endl;
}
void BankAccount::deposit(double cash)
{
balance += cash;
}
void BankAccount::withdraw(double cash)
{
balance -= cash;
}
Code - Program
2 - Here is a rather simple class definition:
class Person {
private:
static const LIMIT = 25;
string lname; // Person’s last name
char fname[LIMIT]; // Person’s first name
public:
Person() {lname = ""; fname[0] = ‘\0’; } // #1
Person(const string & ln, const char * fn = "Heyyou"); // #2
// the following methods display lname and fname
void Show() const; // firstname lastname format
void FormalShow() const; // lastname, firstname format
};
(It uses both a string object and a character array so that you can compare how the two forms are used.)
Write a program that completes the implementation by providing code for the undefined methods. The program in which you use the class should also use the three possible constructor calls (no arguments, one argument, and two arguments) and the two display methods. Here’s an example that uses the constructors and methods:
Person one; // use default constructor
Person two("Smythecraft"); // use #2 with one default argument
Person three("Dimwiddy", "Sam"); // use #2, no defaults
one.Show();
cout << endl;
one.FormalShow();
// etc. for two and three
Code - Prototypes
#ifndef _PERSON_H_
#define _PERSON_H_
#include <iostream>
class Person
{
private:
static const int LIMIT = 25;
std::string lname; // Person’s last name
char fname[LIMIT]; // Person’s first name
public:
Person()
{
lname = "";
fname[0] = '\0';
} // #1
Person(const std::string &ln, const char *fn = "Heyyou"); // #2
// the following methods display lname and fname
void Show() const; // firstname lastname format
void FormalShow() const; // lastname, firstname format
};
#endif
Code - Methods
#include "ch10_2.h"
#include <string.h>
Person::Person(const std::string &ln, const char *fn)
{
lname = ln;
// strcpy(fname, fn);
strcpy_s(fname, sizeof(fname), fn);
}
void Person::Show() const
{
std::cout << "\n" << fname;
std::cout << " " << lname;
}
void Person::FormalShow() const
{
std::cout << "\n" << lname;
std::cout << ", " << fname;
}
Code - Program
#include <iostream>
#include "ch10_2.h"
int main()
{
using namespace std;
Person *myMan = new Person;
Person *yourMan = new Person("Jeff");
Person *ourMan = new Person("Jeff", "Coke");
Person staticMan("Live", "Longman");
cout << "\n\nDefault init myMan: ";
myMan->Show();
cout << "\n\nInit yourMan: ";
yourMan->Show();
cout << "\n\nInit ourMan: ";
yourMan->Show();
cout << "\n\nInit ourMan formalshow: ";
yourMan->FormalShow();
cout << "\n\nInit staticMan: ";
yourMan->Show();
delete myMan, yourMan, ourMan;
return 0;
}
3 -
Do Programming Exercise 1 from Chapter 9 but replace the code shown there with
an appropriate golf class declaration. Replace setgolf(golf &, const char,int)
with a constructor with the appropriate argument for providing initial values.
Retain the interactive version of setgolf() but implement it by using the constructor.
(For example, for the code for setgolf(), obtain the data, pass the data to
the constructor to create a temporary object, and assign the temporary object to the
invoking object, which is this.)
Code - Prototypes
#ifndef _GOLF_H_
#define _GOLF_H_
#include <iostream>
#include <cstring>
static const int Len = 40;
class Golf
{
private:
struct sGolf
{
char fullname[Len];
int handicap;
};
sGolf data;
public:
Golf();
~Golf();
// non-interactive version:
// function sets golf structure to provided name, handicap
// using values passed as arguments to the function
void setgolf(const char *name, int hc);
// interactive version:
// function solicits name and handicap from user
// and sets the members of g to the values entered
// returns 1 if name is entered, 0 if name is empty string
int setgolf();
// function resets handicap to new value
void handicap(int hc);
// function displays contents of golf structure
void showgolf();
};
#endif
Code - Methods
#include <iostream>
#include "ch10_3_golf.h"
Golf::Golf()
{
data.fullname[0] = '\0';
data.handicap = 0;
}
Golf::~Golf()
{
}
void Golf::setgolf(const char *name, int hc)
{
strcpy(data.fullname, name);
data.handicap = hc;
}
int Golf::setgolf()
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "\nEnter the name: ";
// std::cin >> data.fullname;
std::cin.getline(data.fullname, Len);
std::cout << "Enter the handicap: ";
// std::cin >> data.handicap;
while (!(std::cin >> data.handicap))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a number: ";
}
// std::cin.get(); // clear the input buffer
if (data.fullname == "")
{
return 0;
}
return 1;
}
void Golf::handicap(int hc)
{
data.handicap = hc;
}
void Golf::showgolf()
{
std::cout << "\t" << data.fullname << "\t\t";
std::cout << data.handicap << std::endl;
}
Code - Program
#include <iostream>
#include "ch10_3_golf.h"
void fnPrintMenu()
{
std::cout
<< "\nPlease select:\n"
<< "\ta) non-interactive version\tb) interactive version\n"
<< "\tc) print all players\t\td) change number of players\n"
<< "\te) quit" << std::endl;
}
int main()
{
char strFullname[40];
int iHandicap{}, iPlayers{1};
char cMenu;
do
{
std::cout << "\nEnter the number of players (default is 1, max is 40): ";
std::cin >> iPlayers;
if (iPlayers > 40 || iPlayers < 1)
{
std::cout << "Invalid number of players, try again\n";
}
} while (iPlayers > 40 || iPlayers < 1);
fnPrintMenu();
std::cin >> cMenu;
Golf *andy = new Golf[40]; // static memory allocation [1/1]
while (true)
{
switch (cMenu)
{
case 'a':
for (int i = 0; i < iPlayers; ++i)
{
// std::cin >> strFullname >> iHandicap;
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cin.getline(strFullname, Len);
while (!(std::cin >> iHandicap))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a number: ";
}
andy[i].setgolf(strFullname, iHandicap);
}
break;
case 'b':
for (size_t i = 0; i < iPlayers; ++i)
{
andy[i].setgolf();
}
break;
case 'c':
std::cout << "\tName \t\t\tHandicap \n";
std::cout << "\t---------------------------------\n";
for (int i = 0; i < iPlayers; ++i)
{
andy[i].showgolf();
}
break;
case 'd':
do
{
std::cout << "\nEnter the number of players (default is 1, max is 40): ";
std::cin >> iPlayers;
if (iPlayers > 40 || iPlayers < 1)
{
std::cout << "Invalid number of players, try again\n";
}
} while (iPlayers > 40 || iPlayers < 1);
break;
case 'e':
std::cout << "Bye-bye!\n";
return 0;
default:
std::cout << "Please enter: a, b, c or d: ";
break;
}
fnPrintMenu();
std::cin >> cMenu;
}
// delete [] andy; // dynamic memory allocation [2/2]
return 0;
}
4 -
Do Programming Exercise 4 from Chapter 9 but convert the Sales structure and
its associated functions to a class and its methods. Replace the setSales(Sales &, double [], int)
function with a constructor. Implement the interactive setSales(Sales &) method by using the constructor.
Keep the class within the namespace SALES.
Code - Prototypes
#include <iostream>
namespace SALES
{
static const int QUARTERS = 4;
class Deals
{
private:
struct Sales
{
double sales[QUARTERS];
double average;
double max;
double min;
};
Sales data;
public:
Deals(/* args */);
~Deals();
// copies the lesser of 4 or n items from the array ar
// to the sales member of s and computes and stores the
// average, maximum, and minimum values of the entered items;
// remaining elements of sales, if any, set to 0
void setSales(const double ar[], int n);
// gathers sales for 4 quarters interactively, stores them
// in the sales member of s and computes and stores the
// average, maximum, and minimum values
void setSales();
// display all information in structure s
void showSales() const;
};
}
Code - Methods
#include <iostream>
#include "ch10_4_sales.h"
SALES::Deals::Deals(/* args */)
{
}
SALES::Deals::~Deals()
{
}
// copies the lesser of 4 or n items from the array ar
// to the sales member of s and computes and stores the
// average, maximum, and minimum values of the entered items;
// remaining elements of sales, if any, set to 0
void SALES::Deals::setSales(const double ar[], int n)
{
if (n > QUARTERS)
return;
data.average = 0;
data.min = ar[0];
data.max = ar[0];
for (int i = 0; i < n; ++i)
{
if (i < (n - 1))
{
if (data.min > ar[i + 1])
data.min = ar[i + 1];
if (data.max < ar[i + 1])
data.max = ar[i + 1];
}
data.sales[i] = ar[i];
data.average += ar[i];
}
data.average /= n;
}
// gathers sales for 4 quarters interactively, stores them
// in the sales member of s and computes and stores the
// average, maximum, and minimum values
void SALES::Deals::setSales()
{
data.average = 0;
data.min = 0;
data.max = 0;
std::cout << "\nSet sales for quarters: ";
for (int i = 0; i < QUARTERS; ++i)
{
std::cout << "\n-> sale " << i << " : ";
while (!(std::cin >> data.sales[i]))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a number: ";
}
}
data.min = data.sales[0];
for (int i = 0; i < QUARTERS; ++i)
{
if (i < (QUARTERS - 1))
{
if (data.min > data.sales[i + 1])
data.min = data.sales[i + 1];
if (data.max < data.sales[i + 1])
data.max = data.sales[i + 1];
}
data.average += data.sales[i];
}
data.average /= QUARTERS;
}
// display all information in structure s
void SALES::Deals::showSales() const
{
std::cout << "\n\n";
std::cout << "\t Average: \t" << data.average;
std::cout << "\t Max: \t" << data.max;
std::cout << "\t Min: \t" << data.min << "\n";
for (int i = 0; i < QUARTERS; i++)
std::cout << "\t Sale [" << i << "] : \t" << data.sales[i];
}
Code - Program
#include <iostream>
#include "ch10_4_sales.h"
using namespace SALES;
void fnPrintMenu()
{
std::cout
<< "\nPlease select:\n"
<< "\ta) non-interactive version\tb) interactive version\n"
<< "\tc) print all sales"
<< "\t\td) quit" << std::endl;
}
int main(){
char cMenu;
Deals *mySales = new Deals[2];
fnPrintMenu();
std::cin >> cMenu;
while (true)
{
switch (cMenu)
{
case 'a':
double temp[QUARTERS];
for (int i = 0; i < QUARTERS; ++i)
{
while (!(std::cin >> temp[i]))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a number: ";
}
}
mySales[0].setSales(temp, QUARTERS);
break;
case 'b':
mySales[1].setSales();
break;
case 'c':
for (int i = 0; i < 2; ++i)
mySales[i].showSales();
break;
case 'd':
// break;
// case 'e':
std::cout << "Bye-bye!\n";
return 0;
default:
std::cout << "Please enter: a, b, c or e: ";
break;
}
fnPrintMenu();
std::cin >> cMenu;
}
delete[] mySales;
return 0;
}
/*
The first file should be a header file that contains the namespace.The second file
should be a source code file that extends the namespace to provide definitions for
the three prototyped functions. The third file should declare two Sales objects. It
should use the interactive version of setSales() to provide values for one structure
and the non-interactive version of setSales() to provide values for the second
structure. It should display the contents of both structures by using
showSales().
*/
5 - Consider the following structure declaration:
Write a program that adds and removes customer structures from a stack, represented by a Stack class declaration. Each time a customer is removed, his or her payment should be added to a running total, and the running total should be reported.
Note: You should be able to use the Stack class unaltered; just change the typedef declaration so that Item is type customer instead of unsigned long.
Code - Prototypes
// stack.h -- class definition for the stack ADT
#ifndef STACK_H_
#define STACK_H_
struct Customer {
char fullname[35];
double payment;
};
class Stack
{
private:
enum
{
MAX = 10
}; // constant specific to class
Customer Client[MAX]; // holds stack structures
int top; // index for top stack item
public:
Stack();
bool isempty() const;
bool isfull() const;
// push() returns false if stack already is full, true otherwise
bool push(const Customer &item); // add item to stack
// pop() returns false if stack already is empty, true otherwise
bool pop(Customer &item); // pop top into item
};
#endif
Code - Methods
// stack.cpp -- Stack member functions
#include "ch10_5_buisness.h"
Stack::Stack() // create an empty stack
{
top = 0;
}
bool Stack::isempty() const
{
return top == 0;
}
bool Stack::isfull() const
{
return top == MAX;
}
bool Stack::push(const Customer &item)
{
if (top < MAX)
{
Client[top++] = item;
return true;
}
else
return false;
}
bool Stack::pop(Customer &item)
{
if (top > 0)
{
item = Client[--top];
return true;
}
else
return false;
}
/*
The default constructor guarantees that all stacks are created empty.The code for
pop() and push() guarantees that the top of the stack is managed properly.
*/
Code - Program
// stacker.cpp -- testing the Stack class
#include <iostream>
#include <cctype> // or ctype.h
#include "ch10_5_buisness.h"
int main()
{
using namespace std;
Stack st; // create an empty stack
char ch;
Customer po;
long double dRunningTotal{};
cout << "Please enter A to add a purchase order,\n"
<< "P to process a PO, or Q to quit.\n";
while (cin >> ch && toupper(ch) != 'Q')
{
while (cin.get() != '\n')
continue;
if (!isalpha(ch))
{
cout << '\a';
continue;
}
switch (ch)
{
case 'A':
case 'a':
cout << "Enter a name of a Customer to add: ";
cin.getline(po.fullname, 35);
if (!isalpha(ch))
{
cout << '\a';
continue;
}
cout << "Enter a PO price: ";
while (!(cin >> po.payment))
{
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
cin.get(); // clear the input buffer
if (st.isfull())
cout << "stack already full\n";
else
st.push(po);
break;
case 'P':
case 'p':
if (st.isempty())
cout << "stack already empty\n";
else
{
st.pop(po);
dRunningTotal += po.payment;
cout << "PO of a " << po.fullname << " popped\n";
cout << "PO " << po.payment << "$ added\n";
cout << "Running total = " << dRunningTotal << "$\n";
}
break;
}
cout << "\nPlease enter A to add a purchase order,\n"
<< "P to process a PO, or Q to quit.\n";
}
cout << "Bye\n";
return 0;
}
6 - Here’s a class declaration:
class Move
{
private:
double x;
double y;
public:
Move(double a = 0, double b = 0); // sets x, y to a, b
showmove() const; // shows current x, y values
Move add(const Move & m) const;
// this function adds x of m to x of invoking object to get new x,
// adds y of m to y of invoking object to get new y, creates a new
// move object initialized to new x, y values and returns it
reset(double a = 0, double b = 0); // resets x,y to a, b
};
Create member function definitions and a program that exercises the class.
Code - Prototypes
#ifndef _MOVE_H_
#define _MOVE_H_
class Move
{
private:
double x;
double y;
public:
Move(double a = 0, double b = 0); // sets x, y to a, b
void showmove() const; // shows current x, y values
Move add(const Move &m) const;
// this function adds x of m to x of invoking object to get new x,
// adds y of m to y of invoking object to get new y, creates a new
// move object initialized to new x, y values and returns it
void reset(double a = 0, double b = 0); // resets x,y to a, b
};
#endif
Code - Methods
#include <iostream>
#include "ch10_6_move.h"
// sets x, y to a, b
Move::Move(double a, double b)
{
x = a;
y = b;
}
// shows current x, y values
void Move::showmove() const
{
std::cout << "\n x : " << x;
std::cout << "\n y : " << y;
std::cout << std::endl;
}
// this function adds x of m to x of invoking object to get new x,
// adds y of m to y of invoking object to get new y, creates a new
// move object initialized to new x, y values and returns it
Move Move::add(const Move &m) const
{
Move out;
out.x += m.x;
out.y += m.y;
out.x += this->x;
out.y += this->y;
return out;
}
// resets x,y to a, b
void Move::reset(double a, double b)
{
x = a;
y = b;
}
Code
#include <iostream>
#include "ch10_6_move.h"
int main(){
Move moveA;
Move moveB(10.33, 32.2);
double dVals[4] {21.22, 32.3, 3.33, 9.52};
std::cout << "\nmoveA - vals";
moveA.showmove();
std::cout << "\nmoveB - vals";
moveB.showmove();
std::cout << "\nmoveA - reset to " << dVals[0] << ", " << dVals[1];
moveA.reset(dVals[0], dVals[1]);
moveA.showmove();
std::cout << "\nAdding classes: moveB = moveA + moveB";
moveB = moveA.add(moveB);
std::cout << "\nmoveB - vals";
moveB.showmove();
return 0;
}
7 - A Betelgeusean plorg has these properties:
Data
A plorg has a name with no more than 19 letters.
A plorg has a contentment index (CI), which is an integer.
Operations
A new plorg starts out with a name and a CI of 50.
A plorg’s CI can change.
A plorg can report its name and CI.
The default plorg has the name "Plorga".
Write a Plorg class declaration (including data members and member function prototypes) that represents a plorg. Write the function definitions for the member functions. Write a short program that demonstrates all the features of the Plorg class.
Code - Prototypes
Code - Methods
#include <iostream>
#include <string>
#include "ch10_7_plorg.h"
Plorg::Plorg(std::string newName, int newCI)
{
if (newName.length() > MAX)
{
std::cout << "Too long name - assigning default";
name = "Plorga";
}
else
{
name = newName;
}
CI = newCI;
}
void Plorg::ChangeCI(int newCI)
{
CI = newCI;
}
void Plorg::Report()
{
std::cout << "\nThis Plorg is named: " << name;
std::cout << "\nAnd his contentment index is: " << CI;
}
Code
#include <iostream>
#include "ch10_7_plorg.h"
int main(){
Plorg leDef;
Plorg Fluff("Corgi", 100);
Plorg Hulk("Destroyemovertion", 10);
Plorg Nerd("Book", 30);
std::cout << "\n\n\tReport: ";
std::cout << "\n leDef: ";
leDef.Report();
std::cout << "\n\n Fluff: ";
Fluff.Report();
std::cout << "\n\n Hulk: ";
Hulk.Report();
std::cout << "\n\n Nerd: ";
Nerd.Report();
std::cout << "\n\n Nerd - changed CI thanks to the unknown device: ";
Nerd.ChangeCI(70);
Nerd.Report();
std::cout << "\n\nBye Bye!\n";
return 0;
}
8 - You can describe a simple list as follows:
- The simple list can hold zero or more items of some particular type.
- You can create an empty list.
- You can add items to the list.
- You can determine whether the list is empty.
- You can determine whether the list is full.
- You can visit each item in the list and perform some action on it.
As you can see, this list really is simple; it doesn’t allow insertion or deletion, for example.
Design a List class to represent this abstract type. You should provide a list.h
header file with the class declaration and a list.cpp file with the class method
implementations. You should also create a short program that utilizes your design.
The main reason for keeping the list specification simple is to simplify this programming exercise.You can implement the list as an array or, if you’re familiar with the data type, as a linked list. But the public interface should not depend on your choice.That is, the public interface should not have array indices, pointers to nodes, and so on. It should be expressed in the general concepts of creating a list, adding an item to the list, and so on.The usual way to handle visiting each item and performing an action is to use a function that takes a function pointer as an argument:
Here pf points to a function (not a member function) that takes a reference to Item
argument, where Item is the type for items in the list.The visit() function applies
this function to each item in the list.You can use the Stack class as a general guide.
Code - Program
#include <iostream>
#include <cctype> // or ctype.h
#include "ch10_8_list.h"
int main()
{
using namespace std;
List st; // create an empty stack
char ch;
cout << "Please enter A to add element to the list,\n"
<< "D to display values of all elements.\n"
<< "M to modify value of selected element.\n"
<< "R to remove element from the list.\n"
<< "Q to exit the program.\n";
while (cin >> ch && toupper(ch) != 'Q')
{
while (cin.get() != '\n')
continue;
if (!isalpha(ch))
{
cout << '\a';
continue;
}
switch (ch)
{
case 'A':
case 'a':
if (st.isFull())
cout << "list already full\n";
else
{
cout << "Enter value of element to the list: ";
int tmpVal{};
while (!(cin >> tmpVal))
{
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
cin.get(); // clear the input buffer
st.add(tmpVal);
}
break;
case 'D':
case 'd':
st.display();
break;
case 'M':
case 'm':
{
int tmpIdx{};
int tmpVal{};
cout << "Enter the index of list element to change: ";
while (!(cin >> tmpIdx))
{
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
cin.get(); // clear the input buffer
cout << "Enter value of element to the list: ";
while (!(cin >> tmpVal))
{
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
cin.get(); // clear the input buffer
st.modify(tmpIdx, tmpVal);
break;
}
case 'R':
case 'r':
if (st.isEmpty())
cout << "list already empty\n";
else
st.pop();
break;
}
cout << "\nPlease enter A to add element to the list,\n"
<< "D to display values of all elements.\n"
<< "M to modify value of selected element.\n"
<< "R to remove element from the list.\n"
<< "Q to exit the program.\n";
}
cout << "Bye\n";
return 0;
}
Code - Prototypes
Code - Methods
#include <iostream>
#include "ch10_8_list.h"
List::List()
{
}
List::List(int valTab[], int numEl)
{
if (numEl > MAX)
{
std::cout << "More elements than max allowed";
return;
}
for (int i{}; i < numEl; ++i)
{
dataVal[i] = valTab[i];
++top;
}
}
List::~List()
{
}
bool List::isEmpty()
{
return top == 0;
}
bool List::isFull()
{
return top == MAX;
}
bool List::add(int elVal)
{
if (top < MAX)
{
dataVal[top++] = elVal;
return true;
}
else
return false;
}
bool List::pop()
{
if (top > 0)
{
dataVal[top--] = 0;
return true;
}
else
return false;
}
void List::display()
{
for (int i{}; i < top; ++i)
std::cout << "\nItem [" << i << "]: " << dataVal[i];
}
bool List::modify(int elNum, int newVal)
{
if (elNum >= top)
{
std::cout << "Item does not exist";
return false;
}
std::cout << "\nItem [" << elNum << "]: " << dataVal[elNum];
std::cout << "\nChanged value to:";
dataVal[elNum] = newVal;
std::cout << "\nItem [" << elNum << "]: " << dataVal[elNum];
return true;
}
Chapter 11
1 - Modify Listing 11.15 (randwalk.cpp) so that it writes the successive locations of the random walker into a file. Label each position with the step number.Also have the program write the initial conditions (target distance and step size) and the summarized results to the file.The file contents might look like this:
Target Distance: 100, Step Size: 20
0: (x,y) = (0, 0)
1: (x,y) = (-11.4715, 16.383)
2: (x,y) = (-8.68807, -3.42232)
...
26: (x,y) = (42.2919, -78.2594)
27: (x,y) = (58.6749, -89.7309)
After 27 steps, the subject has the following location:
(x,y) = (58.6749, -89.7309)
or
(m,a) = (107.212, -56.8194)
Average outward distance per step = 3.97081
Program
#include <iostream>
#include <cstdlib> // rand(), srand() prototypes
#include <ctime> // time() prototype
#include "ch11_1_vect.h"
#include <fstream>
int main()
{
using namespace std;
using VECTOR::Vector;
srand(time(0)); // seed random-number generator
double direction;
Vector step;
Vector result(0.0, 0.0);
unsigned long steps = 0;
double target;
double dstep;
// File handling
ofstream outFile;
outFile.open("./ch11_1_randwalk.txt");
if (!outFile.is_open())
{
cout << "Could not open file" << endl;
cout << "Terminate program" << endl;
exit(EXIT_FAILURE);
}
cout << "Enter target distance (q to quit): ";
while (cin >> target)
{
cout << "Enter step length: ";
if (!(cin >> dstep))
break;
// Write initial conditions to file
if (outFile.good())
{
outFile << "Target Distance: " << target;
outFile << ", Step Size: " << dstep << endl;
}
while (result.magval() < target)
{
direction = rand() % 360;
step.reset(dstep, direction, Vector::POL);
result = result + step;
if (outFile.good())
outFile << steps << ": (x,y) = (" << result.xval() << ", " << result.yval() << ")" << endl;
steps++;
}
cout << "After " << steps <<
" steps, the subject has the following location:\n";
cout << result << endl;
if (outFile.good())
{
outFile << "After " << steps <<
" steps, the subject has the following location:\n" <<
result << endl;
}
result.polar_mode();
cout << " or\n"
<< result << endl;
cout << "Average outward distance per step = "
<< result.magval() / steps << endl;
if (outFile.good())
{
outFile << " or\n" << result << endl;
outFile << "Average outward distance per step = " <<
result.magval() / steps << endl;
}
steps = 0;
result.reset(0.0, 0.0);
cout << "Enter target distance (q to quit): ";
}
cout << "Bye!\n";
cin.clear();
while (cin.get() != '\n')
continue;
return 0;
}
/*
Modify Listing 11.15 so that it writes the successive locations of the random walker
into a file. Label each position with the step number. Also have the program write
the initial conditions (target distance and step size) and the summarized results to
the file. The file contents might look like this:
Target Distance: 100, Step Size: 20
0: (x,y) = (0, 0)
1: (x,y) = (-11.4715, 16.383)
2: (x,y) = (-8.68807, -3.42232)
...
26: (x,y) = (42.2919, -78.2594)
27: (x,y) = (58.6749, -89.7309)
After 27 steps, the subject has the following location:
(x,y) = (58.6749, -89.7309)
or
(m,a) = (107.212, -56.8194)
Average outward distance per step = 3.97081
Listing 11.15 randwalk.cpp
// randwalk.cpp -- using the Vector class
// compile with the vect.cpp file
#include <iostream>
#include <cstdlib> // rand(), srand() prototypes
#include <ctime> // time() prototype
#include "vect.h"
int
main()
{
using namespace std;
using VECTOR::Vector;
srand(time(0)); // seed random-number generator
double direction;
Vector step;
Vector result(0.0, 0.0);
unsigned long steps = 0;
double target;
double dstep;
cout << "Enter target distance (q to quit): ";
while (cin >> target)
{
cout << "Enter step length: ";
if (!(cin >> dstep))
break;
while (result.magval() < target)
{
direction = rand() % 360;
step.reset(dstep, direction, Vector::POL);
result = result + step;
steps++;
}
cout << "After " << steps << " steps, the subject "
"has the following location:\n";
cout << result << endl;
result.polar_mode();
cout << " or\n"
<< result << endl;
cout << "Average outward distance per step = "
<< result.magval() / steps << endl;
steps = 0;
result.reset(0.0, 0.0);
cout << "Enter target distance (q to quit): ";
}
cout << "Bye!\n";
cin.clear();
while (cin.get() != '\n')
continue;
return 0;
}
*/
/*
Here is a sample run of the program in Listings 11.13, 11.14, and 11.15:
Enter target distance (q to quit): 50
Enter step length: 2
After 253 steps, the subject has the following location:
(x,y) = (46.1512, 20.4902)
or
(m,a) = (50.495, 23.9402)
Average outward distance per step = 0.199587
Enter target distance (q to quit): 50
Enter step length: 2
After 951 steps, the subject has the following location:
(x,y) = (-21.9577, 45.3019)
or
(m,a) = (50.3429, 115.8593)
Average outward distance per step = 0.0529362
Enter target distance (q to quit): 50
Enter step length: 1
After 1716 steps, the subject has the following location:
(x,y) = (40.0164, 31.1244)
or
(m,a) = (50.6956, 37.8755)
Average outward distance per step = 0.0295429
Enter target distance (q to quit): q
Bye!
*/
Prototypes
// vect.h -- Vector class with <<, mode state
#ifndef VECTOR_H_
#define VECTOR_H_
#include <iostream>
namespace VECTOR
{
class Vector
{
public:
enum Mode
{
RECT,
POL
};
// RECT for rectangular, POL for Polar modes
private:
double x; // horizontal value
double y; // vertical value
double mag; // length of vector
double ang; // direction of vector in degrees
Mode mode; // RECT or POL
// private methods for setting values
void set_mag();
void set_ang();
void set_x();
void set_y();
public:
Vector();
Vector(double n1, double n2, Mode form = RECT);
void reset(double n1, double n2, Mode form = RECT);
~Vector();
double xval() const { return x; } // report x value
double yval() const { return y; } // report y value
double magval() const { return mag; } // report magnitude
double angval() const { return ang; } // report angle
void polar_mode(); // set mode to POL
void rect_mode(); // set mode to RECT
// operator overloading
Vector operator+(const Vector &b) const;
Vector operator-(const Vector &b) const;
Vector operator-() const;
Vector operator*(double n) const;
// friends
friend Vector operator*(double n, const Vector &a);
friend std::ostream &
operator<<(std::ostream &os, const Vector &v);
};
} // end namespace VECTOR
#endif
Methods
// vect.cpp -- methods for the Vector class
#include <cmath>
#include "ch11_1_vect.h" // includes <iostream>
using std::atan;
using std::atan2;
using std::cos;
using std::cout;
using std::sin;
using std::sqrt;
namespace VECTOR
{
// compute degrees in one radian
const double Rad_to_deg = 45.0 / atan(1.0);
// should be about 57.2957795130823
// private methods
// calculates magnitude from x and y
void Vector::set_mag()
{
mag = sqrt(x * x + y * y);
}
void Vector::set_ang()
{
if (x == 0.0 && y == 0.0)
ang = 0.0;
else
ang = atan2(y, x);
}
// set x from polar coordinate
void Vector::set_x()
{
x = mag * cos(ang);
}
// set y from polar coordinate
void Vector::set_y()
{
y = mag * sin(ang);
}
// public methods
Vector::Vector() // default constructor
{
x = y = mag = ang = 0.0;
mode = RECT;
}
// construct vector from rectangular coordinates if form is r
// (the default) or else from polar coordinates if form is p
Vector::Vector(double n1, double n2, Mode form)
{
mode = form;
if (form == RECT)
{
x = n1;
y = n2;
set_mag();
set_ang();
}
else if (form == POL)
{
mag = n1;
ang = n2 / Rad_to_deg;
set_x();
set_y();
}
else
{
cout << "Incorrect 3rd argument to Vector() -- ";
cout << "vector set to 0\n";
x = y = mag = ang = 0.0;
mode = RECT;
}
}
// reset vector from rectangular coordinates if form is
// RECT (the default) or else from polar coordinates if
// form is POL
void Vector::reset(double n1, double n2, Mode form)
{
mode = form;
if (form == RECT)
{
x = n1;
y = n2;
set_mag();
set_ang();
}
else if (form == POL)
{
mag = n1;
ang = n2 / Rad_to_deg;
set_x();
set_y();
}
else
{
cout << "Incorrect 3rd argument to Vector() -- ";
cout << "vector set to 0\n";
x = y = mag = ang = 0.0;
mode = RECT;
}
}
Vector::~Vector() // destructor
{
}
void Vector::polar_mode() // set to polar mode
{
mode = POL;
}
void Vector::rect_mode() // set to rectangular mode
{
mode = RECT;
}
// operator overloading
// add two Vectors
Vector Vector::operator+(const Vector &b) const
{
return Vector(x + b.x, y + b.y);
}
// subtract Vector b from a
Vector Vector::operator-(const Vector &b) const
{
return Vector(x - b.x, y - b.y);
}
// reverse sign of Vector
Vector Vector::operator-() const
{
return Vector(-x, -y);
}
// multiply vector by n
Vector Vector::operator*(double n) const
{
return Vector(n * x, n * y);
}
// friend methods
// multiply n by Vector a
Vector operator*(double n, const Vector &a)
{
return a * n;
}
// display rectangular coordinates if mode is RECT,
// else display polar coordinates if mode is POL
std::ostream &operator<<(std::ostream &os, const Vector &v)
{
if (v.mode == Vector::RECT)
os << "(x,y) = (" << v.x << ", " << v.y << ")";
else if (v.mode == Vector::POL)
{
os << "(m,a) = (" << v.mag << ", "
<< v.ang * Rad_to_deg << ")";
}
else
os << "Vector object mode is invalid";
return os;
}
} // end namespace VECTOR
2 -
Modify the Vector class header and implementation files (Listings 11.13 and 11.14)
so that the magnitude and angle are no longer stored as data components. Instead,
they should be calculated on demand when the magval() and angval() methods
are called. You should leave the public interface unchanged (the same public methods
with the same arguments) but alter the private section, including some of the
private method and the method implementations. Test the modified version with
Listing 11.15, which should be left unchanged because the public interface of the
Vector class is unchanged.
Code - program
#include <iostream>
#include <cstdlib> // rand(), srand() prototypes
#include <ctime> // time() prototype
#include "ch11_2_vect.h"
#include <fstream>
int main()
{
using namespace std;
using VECTOR::Vector;
srand(time(0)); // seed random-number generator
double direction;
Vector step;
Vector result(0.0, 0.0);
unsigned long steps = 0;
double target;
double dstep;
// File handling
ofstream outFile;
outFile.open("./ch11_2_randwalk.txt");
if (!outFile.is_open())
{
cout << "Could not open file" << endl;
cout << "Terminate program" << endl;
exit(EXIT_FAILURE);
}
cout << "Enter target distance (q to quit): ";
while (cin >> target)
{
cout << "Enter step length: ";
if (!(cin >> dstep))
break;
// Write initial conditions to file
if (outFile.good())
{
outFile << "Target Distance: " << target;
outFile << ", Step Size: " << dstep << endl;
}
while (result.magval() < target)
{
direction = rand() % 360;
step.reset(dstep, direction, Vector::POL);
result = result + step;
if (outFile.good())
outFile << steps << ": (x,y) = (" << result.xval() << ", " << result.yval() << ")" << endl;
steps++;
}
cout << "After " << steps <<
" steps, the subject has the following location:\n";
cout << result << endl;
if (outFile.good())
{
outFile << "After " << steps <<
" steps, the subject has the following location:\n" <<
result << endl;
}
result.polar_mode();
cout << " or\n"
<< result << endl;
cout << "Average outward distance per step = "
<< result.magval() / steps << endl;
if (outFile.good())
{
outFile << " or\n" << result << endl;
outFile << "Average outward distance per step = " <<
result.magval() / steps << endl;
}
steps = 0;
result.reset(0.0, 0.0);
cout << "Enter target distance (q to quit): ";
}
cout << "Bye!\n";
cin.clear();
while (cin.get() != '\n')
continue;
return 0;
}
/*
Modify the <code>Vector</code> class header and implementation files (Listings 11.13 and 11.14)
so that the magnitude and angle are no longer stored as data components. Instead,
they should be calculated on demand when the <code>magval()</code> and <code>angval()</code> methods
are called. You should leave the public interface unchanged (the same public methods
with the same arguments) but alter the private section, including some of the
private method and the method implementations. Test the modified version with
Listing 11.15, which should be left unchanged because the public interface of the
<code>Vector</code> class is unchanged.
*/
Code - prototypes [Test with ch11_2_base.cpp]
// vect.h -- Vector class with <<, mode state
#ifndef VECTOR_H_
#define VECTOR_H_
#include <iostream>
#include <cmath>
namespace VECTOR
{
class Vector
{
public:
enum Mode
{
RECT,
POL
};
// RECT for rectangular, POL for Polar modes
private:
double x; // horizontal value
double y; // vertical value
Mode mode; // RECT or POL
// private methods for setting values
void set_x();
void set_y();
public:
Vector();
Vector(double n1, double n2, Mode form = RECT);
void reset(double n1, double n2, Mode form = RECT);
~Vector();
double xval() const { return x; } // report x value
double yval() const { return y; } // report y value
double magval() const { return std::sqrt(x * x + y * y); } // report magnitude
double angval() const { return ((x == 0.0 && y == 0.0) ? 0.0 : std::atan2(y, x)); } // report angle
void polar_mode(); // set mode to POL
void rect_mode(); // set mode to RECT
// operator overloading
Vector operator+(const Vector &b) const;
Vector operator-(const Vector &b) const;
Vector operator-() const;
Vector operator*(double n) const;
// friends
friend Vector operator*(double n, const Vector &a);
friend std::ostream &
operator<<(std::ostream &os, const Vector &v);
};
} // end namespace VECTOR
#endif
Code - methods
// vect.cpp -- methods for the Vector class
#include "ch11_2_vect.h" // includes <iostream>
using std::atan;
using std::atan2;
using std::cos;
using std::cout;
using std::sin;
using std::sqrt;
namespace VECTOR
{
// compute degrees in one radian
const double Rad_to_deg = 45.0 / atan(1.0);
// should be about 57.2957795130823
// private methods
// calculates magnitude from x and y
// void Vector::set_mag()
// {
// mag = sqrt(x * x + y * y);
// }
// void Vector::set_ang()
// {
// if (x == 0.0 && y == 0.0)
// ang = 0.0;
// else
// ang = atan2(y, x);
// }
// set x from polar coordinate
void Vector::set_x()
{
x = sqrt(x * x + y * y) * cos((x == 0.0 && y == 0.0) ? (0.0) : atan2(y, x));
}
// set y from polar coordinate
void Vector::set_y()
{
y = sqrt(x * x + y * y) * sin((x == 0.0 && y == 0.0) ? (0.0) : atan2(y, x));
}
// public methods
Vector::Vector() // default constructor
{
x = y = 0.0;
mode = RECT;
}
// construct vector from rectangular coordinates if form is r
// (the default) or else from polar coordinates if form is p
Vector::Vector(double n1, double n2, Mode form)
{
mode = form;
if (form == RECT)
{
x = n1;
y = n2;
// set_mag();
// set_ang();
}
else if (form == POL)
{
// sqrt(x * x + y * y) = n1;
// (x == 0.0 && y == 0.0) ? (0.0) : atan2(y, x) = n2 / Rad_to_deg;
x = n1 * cos(n2 / Rad_to_deg);
y = n1 * sin(n2 / Rad_to_deg);
set_x();
set_y();
}
else
{
cout << "Incorrect 3rd argument to Vector() -- ";
cout << "vector set to 0\n";
x = y = 0.0;
mode = RECT;
}
}
// reset vector from rectangular coordinates if form is
// RECT (the default) or else from polar coordinates if
// form is POL
void Vector::reset(double n1, double n2, Mode form)
{
mode = form;
if (form == RECT)
{
x = n1;
y = n2;
// set_mag();
// set_ang();
}
else if (form == POL)
{
// sqrt(x * x + y * y) = n1;
// (x == 0.0 && y == 0.0) ? (0.0) : atan2(y, x) = n2 / Rad_to_deg;
//
//Both options are essentially doing the same thing, which is converting
//the angle from degrees to radians and then using it in the cosine function. The difference is just in the way they are written.
// 1.
// double theta = n2 * (3.14159265 / Rad_to_deg);
// x = n1 * cos(theta);
// y = n1 * sin(theta);
// 2.
// x = n1 * cos(n2 / Rad_to_deg);
// y = n1 * sin(n2 / Rad_to_deg);
x = n1 * cos(n2 / Rad_to_deg);
y = n1 * sin(n2 / Rad_to_deg);
set_x();
set_y();
}
else
{
cout << "Incorrect 3rd argument to Vector() -- ";
cout << "vector set to 0\n";
x = y = 0.0;
mode = RECT;
}
}
Vector::~Vector() // destructor
{
}
void Vector::polar_mode() // set to polar mode
{
mode = POL;
}
void Vector::rect_mode() // set to rectangular mode
{
mode = RECT;
}
// operator overloading
// add two Vectors
Vector Vector::operator+(const Vector &b) const
{
return Vector(x + b.x, y + b.y);
}
// subtract Vector b from a
Vector Vector::operator-(const Vector &b) const
{
return Vector(x - b.x, y - b.y);
}
// reverse sign of Vector
Vector Vector::operator-() const
{
return Vector(-x, -y);
}
// multiply vector by n
Vector Vector::operator*(double n) const
{
return Vector(n * x, n * y);
}
// friend methods
// multiply n by Vector a
Vector operator*(double n, const Vector &a)
{
return a * n;
}
// display rectangular coordinates if mode is RECT,
// else display polar coordinates if mode is POL
std::ostream &operator<<(std::ostream &os, const Vector &v)
{
if (v.mode == Vector::RECT)
os << "(x,y) = (" << v.x << ", " << v.y << ")";
else if (v.mode == Vector::POL)
{
os << "(m,a) = (" << sqrt(v.x * v.x + v.y * v.y) << ", "
<< ((v.x == 0.0 && v.y == 0.0) ? (0.0) : atan2(v.y, v.x)) * Rad_to_deg << ")";
}
else
os << "Vector object mode is invalid";
return os;
}
} // end namespace VECTOR
3 - Modify Listing 11.15 (randwalk.cpp) so that instead of reporting the results of a single trial for a particular target/step combination, it reports the highest, lowest, and average number of steps for N trials, where N is an integer entered by the user.
Code
#include <iostream>
#include <cstdlib> // rand(), srand() prototypes
#include <ctime> // time() prototype
#include "ch11_3_vect.h"
#include <fstream>
// struct for highest, lowest, and average number of steps for trials
struct trialsData{
int iNumTrials;
double dMax;
double dMin;
double dAvg;
};
int main()
{
using namespace std;
using VECTOR::Vector;
srand(time(0)); // seed random-number generator
double direction;
Vector step;
Vector prevStep;
Vector result(0.0, 0.0);
unsigned long steps = 0;
double target;
double dstep;
double dTmpMin;
double dTmpMax;
trialsData tData;
tData.dMax = 0;
tData.dMin = 0;
tData.dAvg = 0;
cout << "Enter target distance (q to quit): ";
while (cin >> target)
{
cout << "Enter step length: ";
if (!(cin >> dstep))
break;
cout << "Enter number of trials: ";
if (!(cin >> tData.iNumTrials))
break;
for (int i = 0; i < tData.iNumTrials; i++)
{
while (result.magval() < target)
{
prevStep = step;
direction = rand() % 360;
step.reset(dstep, direction, Vector::POL);
result = result + step;
steps++;
}
cout << "After " << steps << " steps, the subject has the following location:\n";
cout << result << endl;
result.polar_mode();
cout << " or\n"
<< result << endl;
cout << "Average outward distance per step = "
<< result.magval() / steps << endl;
tData.dAvg = tData.dAvg + steps;
tData.dMax = tData.dMax > steps ? tData.dMax : steps;
if(tData.dMin > 0)
tData.dMin = tData.dMin < steps ? tData.dMin : steps;
else
tData.dMin = steps;
steps = 0;
result.reset(0.0, 0.0);
}
tData.dAvg = tData.dAvg / tData.iNumTrials;
cout << "\n\nNumber of steps for " << tData.iNumTrials << " trials:\n";
cout << "\t Highest:\t " << tData.dMax << endl;
cout << "\t Lowest:\t " << tData.dMin << endl;
cout << "\t Average:\t " << tData.dAvg << endl << endl;
cout << "Enter target distance (q to quit): ";
}
cout << "Bye!\n";
cin.clear();
while (cin.get() != '\n')
continue;
return 0;
}
4 -
Rewrite the final Time class example (mytime2.h, mytime2.cpp, and usetime2.cpp) so that all
the overloaded operators are implemented using friend functions.
Code - prototypes
// mytime2.h -- Time class after operator overloading
#ifndef MYTIME3_H_
#define MYTIME3_H_
#include <iostream>
class Time
{
private:
int hours;
int minutes;
public:
Time();
Time(int h, int m = 0);
void AddMin(int m);
void AddHr(int h);
void Reset(int h = 0, int m = 0);
friend Time operator+(const Time &t_inp, const Time &t);
friend Time operator-(const Time &t_inp, const Time &t);
friend Time operator*(double mult, const Time &t);
friend Time operator*(const Time &t,double mult){
return mult*t;
}
friend std::ostream &operator<<(std::ostream &os, const Time &t);
};
#endif
Code - methods
// mytime1.cpp -- implementing Time methods
#include <iostream>
#include "ch11_4_time.h"
Time::Time()
{
hours = minutes = 0;
}
Time::Time(int h, int m)
{
hours = h;
minutes = m;
}
void Time::AddMin(int m)
{
minutes += m;
hours += minutes / 60;
minutes %= 60;
}
void Time::AddHr(int h)
{
hours += h;
}
void Time::Reset(int h, int m)
{
hours = h;
minutes = m;
}
Time operator+(const Time &t_inp, const Time &t)
{
Time sum;
sum.minutes = t_inp.minutes + t.minutes;
sum.hours = t_inp.hours + t.hours + sum.minutes / 60;
sum.minutes %= 60;
return sum;
}
Time operator-(const Time &t_inp, const Time &t)
{
Time diff;
int tot1, tot2;
tot1 = t.minutes + 60 * t.hours;
tot2 = t_inp.minutes + 60 * t_inp.hours;
diff.minutes = (tot2 - tot1) % 60;
diff.hours = (tot2 - tot1) / 60;
return diff;
}
Time operator*(double mult, const Time &t)
{
Time result;
long totalminutes = t.hours * mult * 60 + t.minutes * mult;
result.hours = totalminutes / 60;
result.minutes = totalminutes % 60;
return result;
}
std::ostream &operator<<(std::ostream &os, const Time &t)
{
os << t.hours << " hours, " << t.minutes << " minutes";
return os;
}
Code - program
// usetime3.cpp -- using the fourth draft of the Time class
// compile usetime3.cpp and mytime3.cpp together
#include <iostream>
#include "ch11_4_time.h"
int main()
{
using std::cout;
using std::endl;
Time aida(3, 35);
Time tosca(2, 48);
Time temp;
cout << "Aida and Tosca:\n";
cout << aida << "; " << tosca << endl;
temp = aida + tosca; // operator+()
cout << "Aida + Tosca: " << temp << endl;
temp = aida - tosca; // operator+()
cout << "Aida - Tosca: " << temp << endl;
temp = aida * 1.17; // member operator*()
cout << "Aida * 1.17: " << temp << endl;
cout << "10.0 * Tosca: " << 10.0 * tosca << endl;
return 0;
}
/*
Aida and Tosca:
3 hours, 35 minutes; 2 hours, 48 minutes
Aida + Tosca: 6 hours, 23 minutes
Aida * 1.17: 4 hours, 11 minutes
10.0 * Tosca: 28 hours, 0 minutes
*/
5 -
Rewrite the Stonewt class (stonewt.h and stonewt.cpp) so that it has a state member
that governs whether the object is interpreted in stone form, integer pounds form,
or floating-point pounds form. Overload the << operator to replace the
show_stn() and show_lbs() methods. Overload the addition, subtraction, and
multiplication operators so that one can add, subtract, and multiply Stonewt values.
Test your class with a short program that uses all the class methods and friends.
Code - program
// stone.cpp -- user-defined conversions
#include <iostream>
using std::cout;
using std::endl;
#include "ch11_5_stone.h"
void display(const Stonewt &st, int n);
int main()
{
Stonewt incognito = 275; // uses constructor to initialize
Stonewt wolfe(285.7); // same as Stonewt wolfe = 285.7;
Stonewt taft(21, 8);
Stonewt informalStone(30, Stonewt::Mode::STONE);
Stonewt formalStone(60.5, Stonewt::Mode::STONE);
Stonewt stupidPound(90.5, Stonewt::Mode::POUND);
Stonewt formalPound(120.5, Stonewt::Mode::POUND_FP);
cout << "informal Stone weight: "
<< informalStone << endl;
cout << "formal Stone weight: "
<< formalStone << endl;
cout << "stupid Pound weight: "
<< stupidPound << endl;
stupidPound.changeMode(Stonewt::Mode::STONE);
cout << "stupid Pound weight: "
<< stupidPound << endl;
cout << "formal Pound weight: "
<< formalPound << endl;
Stonewt addedStone(0, Stonewt::Mode::STONE);
addedStone = formalPound + stupidPound;
cout << "Formal pound + stupid pound = "
<< addedStone << endl;
addedStone = formalPound - stupidPound;
cout << "Formal pound - stupid pound = "
<< addedStone << endl;
addedStone = formalPound * stupidPound;
cout << "Formal pound * stupid pound = "
<< addedStone << endl;
// cout << "The celebrity weighed ";
// incognito.show_stn();
// cout << "The detective weighed ";
// wolfe.show_stn();
// cout << "The President weighed ";
// taft.show_lbs();
// incognito = 276.8; // uses constructor for conversion
// taft = 325; // same as taft = Stonewt(325);
// cout << "After dinner, the celebrity weighed ";
// incognito.show_stn();
// cout << "After dinner, the President weighed ";
// taft.show_lbs();
// display(taft, 2);
// cout << "The wrestler weighed even more.\n";
// display(422, 2);
// cout << "No stone left unearned\n";
return 0;
}
// void display(const Stonewt &st, int n)
// {
// for (int i = 0; i < n; i++)
// {
// cout << "Wow! ";
// st.show_stn();
// }
// }
/*
The celebrity weighed 19 stone, 9 pounds
The detective weighed 20 stone, 5.7 pounds
The President weighed 302 pounds
After dinner, the celebrity weighed 19 stone, 10.8 pounds
After dinner, the President weighed 325 pounds
Wow! 23 stone, 3 pounds
Wow! 23 stone, 3 pounds
The wrestler weighed even more.
Wow! 30 stone, 2 pounds
Wow! 30 stone, 2 pounds
No stone left unearned
*/
Code - Prototypes
// stonewt.h -- definition for the Stonewt class
#ifndef STONEWT_H_
#define STONEWT_H_
#include "ch11_5_stone.h"
class Stonewt
{
public:
enum Mode{
STONE,
POUND, // integer pounds
POUND_FP // floating-point pounds
};
private:
enum
{
Lbs_per_stn = 14
}; // pounds per stone
int stone; // whole stones
double pds_left; // fractional pounds
double pounds; // entire weight in pounds
Mode mode; // Stone, integer pounds or floating-point pounds
public:
Stonewt(double in, Mode form);// constructor for Stonewt with mode object
Stonewt(int in, Mode form) : Stonewt(static_cast<double>(in), form) {};
Stonewt(double lbs); // constructor for double pounds
Stonewt(int stn, double lbs); // constructor for stone, lbs
Stonewt(); // default constructor
~Stonewt();
void changeMode(Mode form);
Stonewt operator+(const Stonewt &s) const;
Stonewt operator-(const Stonewt &s) const;
Stonewt operator*(const Stonewt &s) const;
friend std::ostream &operator<<(std::ostream &os, const Stonewt &stn);
// void show_lbs() const; // show weight in pounds format
// void show_stn() const; // show weight in stone format
};
#endif
Code - Methods
// stonewt.cpp -- Stonewt methods
#include <iostream>
using std::cout;
#include "ch11_5_stone.h"
// construct Stonewt object from double value
Stonewt::Stonewt(double lbs)
{
mode = POUND_FP;
stone = int(lbs) / Lbs_per_stn; // integer division
pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
pounds = lbs;
}
// construct Stonewt object from stone, double values
Stonewt::Stonewt(int stn, double lbs)
{
mode = STONE;
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
}
Stonewt::Stonewt(double in, Mode form){
mode = form;
if(STONE == mode){
stone = in;
pounds = in * Lbs_per_stn;
pds_left = int(pounds) % Lbs_per_stn + pounds - int(pounds);
}
else if(POUND_FP == mode || POUND == mode){
pounds = in;
stone = pounds / Lbs_per_stn;
pds_left = int(pounds) % Lbs_per_stn + pounds - int(pounds);
}
}
Stonewt::Stonewt() // default constructor, wt = 0
{
mode = STONE;
stone = pounds = pds_left = 0;
}
Stonewt::~Stonewt() // destructor
{
}
Stonewt Stonewt::operator+(const Stonewt &s) const{
Stonewt temp;
temp.pounds = pounds + s.pounds;
temp.stone = int(temp.pounds) / Lbs_per_stn;
temp.pds_left = int(pounds + s.pounds) % Lbs_per_stn + (pds_left + s.pds_left) - int(pds_left + s.pds_left);
return temp;
}
Stonewt Stonewt::operator-(const Stonewt &s) const{
Stonewt temp;
temp.pounds = pounds - s.pounds;
temp.stone = int(temp.pounds) / Lbs_per_stn;
temp.pds_left = int(temp.pounds) % Lbs_per_stn + temp.pounds - int(temp.pounds);
return temp;
}
Stonewt Stonewt::operator*(const Stonewt &s) const{
Stonewt temp;
temp.pounds = pounds * s.pounds;
temp.stone = int(temp.pounds) / Lbs_per_stn;
temp.pds_left = int(temp.pounds) % Lbs_per_stn + temp.pounds - int(temp.pounds);
return temp;
}
std::ostream &operator<<(std::ostream &os, const Stonewt &s){
if(s.STONE == s.mode)
os << s.stone << " stone, " << s.pds_left << " pounds";
else if(s.POUND == s.mode)
os << int(s.pounds) << " pounds";
else if(s.POUND_FP == s.mode)
os << s.pounds << " pounds";
return os;
}
// // show weight in stones
// void Stonewt::show_stn() const
// {
// cout << stone << " stone, " << pds_left << " pounds\n";
// }
// // show weight in pounds
// void Stonewt::show_lbs() const
// {
// cout << pounds << " pounds\n";
// }
void Stonewt::changeMode(Mode form){
mode = form;
}
6 -
Rewrite the Stonewt class (stonewt.h and stonewt.cpp) so that it overloads all six
relational operators (>, >=, ==, <=, <, and != ). The operators should compare the pounds members and return
a type bool value. Write a program that declares an array of six Stonewt objects and
initializes the first three objects in the array declaration. Then it should use a loop
to read in values used to set the remaining three array elements. Then it should
report the smallest element, the largest element, and how many elements are greater
or equal to 11 stone. (The simplest approach is to create a Stonewt object initialized
to 11 stone and to compare the other objects with that object.)
Code - Program
// stone1.cpp -- user-defined conversion functions
// compile with stonewt1.cpp
#include <iostream>
#include "ch11_6_stone.h"
int main()
{
using std::cout;
using std::endl;
Stonewt poppins(9, 2.8); // 9 stone, 2.8 pounds
double p_wt = poppins; // implicit conversion
Stonewt wolfe(285.7); // same as Stonewt wolfe = 285.7;
Stonewt tafte(21, 8);
Stonewt glock(21, 8);
cout << "Convert to double => ";
cout << "Poppins: " << p_wt << " pounds.\n";
cout << "Convert to int => ";
cout << "Poppins: " << int(poppins) << " pounds.\n\n";
cout << "Wolfe weight: " << wolfe << endl;
cout << "Tafte weight: " << tafte << endl;
cout << "glock weight: " << glock << endl;
cout << endl;
std::cout << std::boolalpha;
cout << "Is Wolfe > Tafte?: " << (wolfe > tafte) << endl;
cout << "Is Wolfe < Tafte?: " << (wolfe < tafte) << endl;
cout << "Is Wolfe >= Tafte?: " << (wolfe >= tafte) << endl;
cout << "Is Wolfe <= Tafte?: " << (wolfe <= tafte) << endl;
cout << "Is Wolfe == Tafte?: " << (wolfe == tafte) << endl;
cout << "Is Wolfe != Tafte?: " << (wolfe != tafte) << endl;
cout << endl;
cout << "Is glock > Tafte?: " << (glock > tafte) << endl;
cout << "Is glock < Tafte?: " << (glock < tafte) << endl;
cout << "Is glock >= Tafte?: " << (glock >= tafte) << endl;
cout << "Is glock <= Tafte?: " << (glock <= tafte) << endl;
cout << "Is glock == Tafte?: " << (glock == tafte) << endl;
cout << "Is glock != Tafte?: " << (glock != tafte) << endl;
cout << endl;
std::cout << std::noboolalpha;
return 0;
}
Code - Prototypes
// stonewt1.h -- revised definition for the Stonewt class
#ifndef STONEWT1_H_
#define STONEWT1_H_
#include <iostream>
class Stonewt
{
private:
enum
{
Lbs_per_stn = 14
}; // pounds per stone
int stone; // whole stones
double pds_left; // fractional pounds
double pounds; // entire weight in pounds
public:
Stonewt(double lbs); // construct from double pounds
Stonewt(int stn, double lbs); // construct from stone, lbs
Stonewt(); // default constructor
~Stonewt();
void show_lbs() const; // show weight in pounds format
void show_stn() const; // show weight in stone format
// conversion functions
operator int() const;
operator double() const;
friend std::ostream &operator<<(std::ostream &os, const Stonewt &stn);
inline bool operator>(const Stonewt &s) const
{
return (pounds > s.pounds) ? true : false;
}
inline bool operator<(const Stonewt &s) const
{
return (pounds < s.pounds) ? true : false;
}
inline bool operator>=(const Stonewt &s) const
{
return (pounds >= s.pounds) ? true : false;
}
inline bool operator<=(const Stonewt &s) const
{
return (pounds <= s.pounds) ? true : false;
}
inline bool operator==(const Stonewt &s) const
{
return (pounds == s.pounds) ? true : false;
}
inline bool operator!=(const Stonewt &s) const
{
return (pounds != s.pounds) ? true : false;
}
};
#endif
Code - Methods
// stonewt1.cpp -- Stonewt class methods + conversion functions
using std::cout;
#include "ch11_6_stone.h"
// construct Stonewt object from double value
Stonewt::Stonewt(double lbs)
{
stone = int(lbs) / Lbs_per_stn; // integer division
pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
pounds = lbs;
}
// construct Stonewt object from stone, double values
Stonewt::Stonewt(int stn, double lbs)
{
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
}
Stonewt::Stonewt() // default constructor, wt = 0
{
stone = pounds = pds_left = 0;
}
Stonewt::~Stonewt() // destructor
{
}
// show weight in stones
void Stonewt::show_stn() const
{
cout << stone << " stone, " << pds_left << " pounds\n";
}
// show weight in pounds
void Stonewt::show_lbs() const
{
cout << pounds << " pounds\n";
}
// conversion functions
Stonewt::operator int() const
{
return int(pounds + 0.5);
}
Stonewt::operator double() const
{
return pounds;
}
std::ostream &operator<<(std::ostream &os, const Stonewt &s){
os << s.stone << " stone, " << s.pds_left << " pounds";
return os;
}
7 -
A complex number has two parts: a real part and an imaginary part. One way to
write an imaginary number is this: (3.0, 4.0). Here 3.0 is the real part and 4.0 is
the imaginary part. Suppose a = (A,Bi) and c = (C,Di). Here are some complex
operations:
- Addition:
a + c = (A + C, (B + D)i) - Subtraction:
a - c = (A - C, (B - D)i) - Multiplication:
a × c = (A × C - B×D, (A×D + B×C)i) - Multiplication:
(x a real number): x × c = (x×C,x×Di) - Conjugation:
~a = (A, - Bi)
Define a complex class so that the following program can use it with correct results:
#include <iostream>
#include "complex0.h" // to avoid confusion with complex.h
using namespace std;
int main()
{
complex a(3.0, 4.0); // initialize to (3,4i)
complex c;
cout << "Enter a complex number (q to quit):\n";
while (cin >> c)
{
cout << "c is " << c << '\n';
cout << "complex conjugate is " << ~c << '\n';
cout << "a is " << a << '\n';
cout << "a + c is " << a + c << '\n';
cout << "a - c is " << a - c << '\n';
cout << "a * c is " << a * c << '\n';
cout << "2 * c is " << 2 * c << '\n';
cout << "Enter a complex number (q to quit):\n";
}
cout << "Done!\n";
return 0;
}
Note that you have to overload the << and >> operators. Standard C++ already has
complex support — rather more extensive than in this example — in a complex
header file, so use complex0.h to avoid conflicts. Use const whenever warranted.
Here is a sample run of the program:
Enter a complex number (q to quit):
real: 10
imaginary: 12
c is (10,12i)
complex conjugate is (10,-12i)
a is (3,4i)
a + c is (13,16i)
a - c is (-7,-8i)
a * c is (-18,76i)
2 * c is (20,24i)
Enter a complex number (q to quit):
real: q
Done!
Code - Program
#include <iostream>
#include "ch11_7_complex.h" // to avoid confusion with complex.h
using namespace std;
int main()
{
complex a(3.0, 4.0); // initialize to (3,4i)
complex c;
cout << "Enter a complex number (q to quit):\n";
while (cin >> c)
{
cout << "c is " << c << '\n';
cout << "complex conjugate is " << ~c << '\n';
cout << "a is " << a << '\n';
cout << "a + c is " << a + c << '\n';
cout << "a - c is " << a - c << '\n';
cout << "a * c is " << a * c << '\n';
cout << "2 * c is " << 2 * c << '\n';
cout << "Enter a complex number (q to quit):\n";
}
cout << "Done!\n";
return 0;
}
Code - Prototypes
#ifndef _COMPLEX_H_
#define _COMPLEX_H_
#include <iostream>
class complex
{
private:
double rNum; // real number
double iNum; // imaginary number
public:
complex();
complex(double r, double i);
~complex();
friend std::ostream& operator<<(std::ostream& os, const complex& c);
friend std::istream& operator>>(std::istream& is, complex& c);
complex operator+(const complex& c) const;
complex operator-(const complex& c) const;
complex operator~() const;
complex operator*(const complex& c) const;
complex operator*(const double c) const;
friend complex operator*(const int num, const complex& c) {
return c * double(num);
}
};
#endif
Code - Methods
#include "ch11_7_complex.h"
complex::complex()
{
rNum = 0;
iNum = 0;
}
complex::complex(double r, double i)
{
rNum = r;
iNum = i;
}
complex::~complex()
{
}
std::ostream& operator<<(std::ostream& os, const complex& c){
os << "(" << c.rNum << "," << c.iNum << "i)";
return os;
}
std::istream& operator>>(std::istream& is, complex& c){
std::cout << "real: ";
is >> c.rNum;
std::cout << "imaginary: ";
is >> c.iNum;
return is;
}
complex complex::operator+(const complex& c) const{
complex temp;
temp.rNum = rNum + c.rNum;
temp.iNum = iNum + c.iNum;
return temp;
}
complex complex::operator-(const complex& c) const{
complex temp;
temp.rNum = rNum - c.rNum;
temp.iNum = iNum - c.iNum;
return temp;
}
// (a+bi)(c+di) = (ac−bd) + (ad+bc)i
complex complex::operator*(const complex& c) const{
complex temp;
temp.rNum = rNum * c.rNum - iNum * c.iNum;
temp.iNum = rNum * c.iNum + iNum * c.rNum;
return temp;
}
complex complex::operator*(const double c) const{
complex temp;
temp.rNum = rNum * c;
temp.iNum = iNum * c;
return temp;
}
complex complex::operator~() const{
complex temp;
temp.rNum = rNum;
temp.iNum = iNum * -1;
return temp;
}
Note that cin >> c, through overloading, now prompts for real and imaginary parts.
Chapter 12
1 - Consider the following class declaration:
class Cow
{
char name[20];
char *hobby;
double weight;
public:
Cow();
Cow(const char *nm, const char *ho, double wt);
Cow(const Cow c &);
Programming Exercises 703 ~Cow();
Cow &operator=(const Cow &c);
void ShowCow() const; // display all cow data
};
Provide the implementation for this class and write a short program that uses all the member functions.
Code - Program
Code - Prototypes
Code - Methods
#include "ch12_1_cow.h"
#include <cstring>
Cow::Cow(){
name[0] = '\0';
hobby = new char[1];
hobby[0] = '\0';
weight = 0;
}
Cow::Cow(const char *nm, const char *ho, double wt){
if(std::strlen(nm) < 20)
std::strcpy(name, nm);
else
name[0] = '\0';
hobby = new char[std::strlen(ho) + 1];
std::strcpy(hobby, ho);
weight = wt;
}
Cow::Cow(const Cow &c)
{
std::strcpy(name, c.name);
hobby = new char[std::strlen(c.hobby) + 1];
std::strcpy(hobby, c.hobby);
weight = c.weight;
}
Cow::~Cow()
{
std::cout << "\nDelete: " << hobby;
delete[] hobby;
}
Cow &Cow::operator=(const Cow &c){
if (this == &c)
return *this;
std::strcpy(name, c.name);
delete[] hobby;
hobby = new char[std::strlen(c.hobby) + 1];
std::strcpy(hobby, c.hobby);
weight = c.weight;
return *this;
}
void Cow::ShowCow() const{
std::cout << "\nName: " << name;
std::cout << "\nHobby: " << hobby;
std::cout << "\nWeight: " << weight;
}
2 -
Enhance the String class declaration (that is, upgrade string1.h to string2.h) by
doing the following:
a. Overload the + operator to allow you to join two strings into one.
b. Provide a stringlow() member function that converts all alphabetic characters
in a string to lowercase. (Don’t forget the cctype family of character functions.)
c. Provide a stringup() member function that converts all alphabetic characters in a string to uppercase.
d. Provide a member function that takes a char argument and returns the number of times the character appears in the string.
Test your work in the following program:
Code - Program
// pe12_2.cpp
#include <iostream>
using namespace std;
#include "ch12_2_str.h"
int main()
{
{
String s1(" and I am a C++ student.");
String s2 = "Please enter your name: ";
String s3;
cout << s2; // overloaded << operator
cin >> s3; // overloaded >> operator
s2 = "My name is " + s3; // overloaded =, + operators
cout << s2 << ".\n";
s2 = s2 + s1;
s2.stringup(); // converts string to uppercase
cout << "The string\n"
<< s2 << "\ncontains " << s2.has('A')
<< " 'A' characters in it.\n";
s1 = "red"; // String(const char *),
// then String & operator=(const String&)
String rgb[3] = {String(s1), String("green"), String("blue")};
cout << "Enter the name of a primary color for mixing light: ";
String ans;
bool success = false;
while (cin >> ans)
{
ans.stringlow(); // converts string to lowercase
for (int i = 0; i < 3; i++)
{
if (ans == rgb[i]) // overloaded == operator
{
cout << "That's right!\n";
success = true;
break;
}
}
if (success)
break;
else
cout << "Try again!\n";
}
cout << "Bye\n";
return 0;
}
}
/*
Please enter your name: Maciej
deleted : My name is
deleted : My name is Maciej
My name is Maciej.
deleted : My name is Maciej and I am a C++ student.
The string
MY NAME IS MACIEJ AND I AM A C++ STUDENT.
contains 5 'A' characters in it.
Enter the name of a primary color for mixing light: red
That's right!
Bye
deleted : red
deleted : blue
deleted : green
deleted : red
deleted : Maciej
deleted : MY NAME IS MACIEJ AND I AM A C++ STUDENT.
deleted : red
*/
Code - Prototypes
// string1.h -- fixed and augmented string class definition
#ifndef STR_H_
#define STR_H_
#include <iostream>
using std::istream;
using std::ostream;
class String
{
private:
char *str; // pointer to string
int len; // length of string
static int num_strings; // number of objects
static const int CINLIM = 80; // cin input limit
public:
// constructors and other methods
String(const char *s); // constructor
String(); // default constructor
String(const String &); // copy constructor
~String(); // destructor
int length() const { return len; }
void stringlow(); // b)
void stringup(); // c)
int has(const char s); // d)
// overloaded operator methods
String &operator=(const String &);
String &operator=(const char *);
String operator+(const String &); // a)
String operator+(const char &cstr); // a) const char [12] + String
char &operator[](int i);
const char &operator[](int i) const;
// overloaded operator friends
friend bool operator<(const String &st, const String &st2);
friend bool operator>(const String &st1, const String &st2);
friend bool operator==(const String &st, const String &st2);
friend ostream &operator<<(ostream &os, const String &st);
friend istream &operator>>(istream &is, String &st);
friend ostream &operator+(String &st, ostream os) { return os + st; }
friend ostream &operator+(ostream &os, String &st)
{
os << st.str;
return os;
};
friend String operator+(const char cstr[], const String &st)
{
String tmp(cstr);
return tmp + st;
};
// static function
static int HowMany();
};
#endif
Code - Methods
// string1.cpp -- String class methods
#include <cstring> // string.h for some
#include "ch12_2_str.h" // includes <iostream>
using std::cin;
using std::cout;
// initializing static class member
int String::num_strings = 0;
// static method
int String::HowMany()
{
return num_strings;
}
// class methods
String::String(const char *s) // construct String from C string
{
len = std::strlen(s); // set size
str = new char[len + 1]; // allot storage
std::strcpy(str, s); // initialize pointer
num_strings++; // set object count
}
String::String() // default constructor
{
len = 4;
str = new char[1];
str[0] = '\0'; // default string
num_strings++;
}
String::String(const String &st)
{
num_strings++; // handle static member update
len = st.len; // same length
str = new char[len + 1]; // allot space
std::strcpy(str, st.str); // copy string to new location
}
String::~String() // necessary destructor
{
--num_strings; // required
cout << "deleted : " << str << "\n";
delete[] str; // required
}
void String::stringlow()
{
for (int i = 0; i < len; i++)
str[i] = tolower(str[i]);
}
void String::stringup()
{
for (int i = 0; i < len; i++)
str[i] = toupper(str[i]);
}
int String::has(const char s)
{
int retVal{};
for (int i = 0; i < len; i++)
if (s == str[i])
++retVal;
return retVal;
}
// overloaded operator methods
// assign a String to a String
String &String::operator=(const String &st)
{
if (this == &st)
return *this;
delete[] str;
len = st.len;
str = new char[len + 1];
std::strcpy(str, st.str);
return *this;
}
// assign a C string to a String
String &String::operator=(const char *s)
{
delete[] str;
len = std::strlen(s);
str = new char[len + 1];
std::strcpy(str, s);
return *this;
}
// a)
String String::operator+(const String &st)
{
String temp;
temp.len = st.len + this->len;
temp.str = new char[temp.len + 1];
std::strcpy(temp.str, this->str);
std::strcat(temp.str, st.str);
return temp;
}
String String::operator+(const char &cstr)
{
String tmp{str};
return *this + tmp;
}
// read-write char access for non-const String
char &String::operator[](int i)
{
return str[i];
}
// read-only char access for const String
const char &String::operator[](int i) const
{
return str[i];
}
// overloaded operator friends
bool operator<(const String &st1, const String &st2)
{
return (std::strcmp(st1.str, st2.str) < 0);
}
bool operator>(const String &st1, const String &st2)
{
return st2 < st1;
}
bool operator==(const String &st1, const String &st2)
{
return (std::strcmp(st1.str, st2.str) == 0);
}
// simple String output
ostream &operator<<(ostream &os, const String &st)
{
os << st.str;
return os;
}
// quick and dirty String input
istream &operator>>(istream &is, String &st)
{
char temp[String::CINLIM];
is.get(temp, String::CINLIM);
if (is)
st = temp;
while (is && is.get() != '\n')
continue;
return is;
}
Test your work in the following program:
// pe12_2.cpp
#include <iostream>
using namespace std;
#include "string2.h"
int main()
{
String s1(" and I am a C++ student.");
String s2 = "Please enter your name: ";
String s3;
cout << s2; // overloaded << operator
cin >> s3; // overloaded >> operator
s2 = "My name is " + s3; // overloaded =, + operators
cout << s2 << ".\n";
s2 = s2 + s1;
s2.stringup(); // converts string to uppercase
cout << "The string\n"
<< s2 << "\ncontains " << s2.has('A')
<< " 'A' characters in it.\n";
s1 = "red"; // String(const char *),
// then String & operator=(const String&)
String rgb[3] = {String(s1), String("green"), String("blue")};
cout << "Enter the name of a primary color for mixing light: ";
String ans;
bool success = false;
while (cin >> ans)
{
ans.stringlow(); // converts string to lowercase
for (int i = 0; i < 3; i++)
{
if (ans == rgb[i]) // overloaded == operator
{
cout << "That's right!\n";
success = true;
break;
}
}
if (success)
break;
else
cout << "Try again!\n";
}
cout << "Bye\n";
return 0;
}
Your output should look like this sample run:
Please enter your name: Fretta Farbo
My name is Fretta Farbo.
The string
MY NAME IS FRETTA FARBO AND I AM A C++ STUDENT.
contains 6 'A' characters in it.
Enter the name of a primary color for mixing light: yellow
Try again!
BLUE
That's right!
Bye
3 -
Rewrite the Stock class, as described in Listings 10.7 (stock20.h) and 10.8 (stock20.cpp) in Chapter 10 so
that it uses dynamically allocated memory directly instead of using string class
objects to hold the stock names. Also replace the show() member function with an
overloaded operator<<() definition. Test the new definition program in Listing
10.9 (usestok2.cpp).
Code - prototypes
// stock20.h -- augmented version
#ifndef STOCK20_H_
#define STOCK20_H_
#include <string>
class Stock
{
private:
std::string *company;
int shares;
double share_val;
double total_val;
void set_tot() { total_val = shares * share_val; }
public:
Stock();
// default constructor
Stock(const std::string &co, long n = 0, double pr = 0.0);
~Stock();
// do-nothing destructor
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
// void show() const;
const Stock &topval(const Stock &s) const;
friend std::ostream &operator<<(std::ostream & os, const Stock & st);
};
#endif
Code - methods
// stock20.cpp -- augmented version
#include <iostream>
#include "ch12_3_stock.h"
// constructors
Stock::Stock()
// default constructor
{
company = new std::string("no name");
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
Stock::Stock(const std::string &co, long n, double pr)
{
company = new std::string(co);
if (n < 0)
{
std::cout << "Number of shares can't be negative; "
<< company << " shares set to 0.\n";
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
// class destructor
Stock::~Stock()
{
delete company;
}
// quiet class destructor
// other methods
void Stock::buy(long num, double price)
{
if (num < 0)
{
std::cout << "Number of shares purchased can't be negative. "
<< "Transaction is aborted.\n";
}
else
{
shares += num;
share_val = price;
set_tot();
}
}
void Stock::sell(long num, double price)
{
using std::cout;
if (num < 0)
{
cout << "Number of shares sold can't be negative. "
<< "Transaction is aborted.\n";
}
else if (num > shares)
{
cout << "You can't sell more than you have! "
<< "Transaction is aborted.\n";
}
else
{
shares -= num;
share_val = price;
set_tot();
}
}
void Stock::update(double price)
{
share_val = price;
set_tot();
}
// void Stock::show() const
// {
// using std::cout;
// using std::ios_base;
// // set format to #.###
// ios_base::fmtflags orig =
// cout.setf(ios_base::fixed, ios_base::floatfield);
// std::streamsize prec = cout.precision(3);
// cout << "Company: " << company
// << " Shares: " << shares << '\n';
// cout << " Share Price: $" << share_val;
// // set format to #.##
// cout.precision(2);
// cout << " Total Worth: $" << total_val << '\n';
// // restore original format
// cout.setf(orig, ios_base::floatfield);
// cout.precision(prec);
// }
std::ostream &operator<<(std::ostream & os, const Stock & st){
using std::ios_base;
// set format to #.###
ios_base::fmtflags orig =
os.setf(ios_base::fixed, ios_base::floatfield);
std::streamsize prec = os.precision(3);
os << "Company: " << *st.company
<< " Shares: " << st.shares << '\n';
os << " Share Price: $" << st.share_val;
// set format to #.##
os.precision(2);
os << " Total Worth: $" << st.total_val << '\n';
// restore original format
os.setf(orig, ios_base::floatfield);
os.precision(prec);
return os;
}
const Stock &Stock::topval(const Stock &s) const
{
if (s.total_val > total_val)
return s;
else
return *this;
}
Code - program
// usestok2.cpp -- using the Stock class
// compile with stock20.cpp
#include <iostream>
#include "ch12_3_stock.h"
const int STKS = 4;
int main()
{
// create an array of initialized objects
Stock stocks[STKS] = {
Stock("NanoSmart", 12, 20.0),
Stock("Boffo Objects", 200, 2.0),
Stock("Monolithic Obelisks", 130, 3.25),
Stock("Fleep Enterprises", 60, 6.5)};
std::cout << "Stock holdings:\n";
int st;
for (st = 0; st < STKS; st++)
std::cout << stocks[st]; // stocks[st].show();
// set pointer to first element
const Stock *top = &stocks[0];
for (st = 1; st < STKS; st++)
top = &top->topval(stocks[st]);
// now top points to the most valuable holding
std::cout << "\nMost valuable holding:\n";
std::cout << *top; // top->show();
return 0;
}
/*
Stock holdings:
Company: NanoSmart Shares: 12
Share Price: $20.000 Total Worth: $240.00
Company: Boffo Objects Shares: 200
Share Price: $2.000 Total Worth: $400.00
Company: Monolithic Obelisks Shares: 130
Share Price: $3.250 Total Worth: $422.50
Company: Fleep Enterprises Shares: 60
Share Price: $6.500 Total Worth: $390.00
Most valuable holding:
Company: Monolithic Obelisks Shares: 130
Share Price: $3.250 Total Worth: $422.50
*/
4 -
Consider the following variation of the Stack class defined in Listing 10.10 (stack.h):
typedef unsigned long Item;
class Stack
{
private:
enum
{
MAX = 10
}; // constant specific to class
Item *pitems; // holds stack items
int size; // number of elements in stack
int top; // index for top stack item
public:
Stack(int n = MAX); // creates stack with n elements
Stack(const Stack &st);
~Stack();
bool isempty() const;
bool isfull() const;
// push() returns false if stack already is full, true otherwise
bool push(const Item &item); // add item to stack
// pop() returns false if stack already is empty, true otherwise
bool pop(Item &item); // pop top into item
Stack &operator=(const Stack &st);
};
As the private members suggest, this class uses a dynamically allocated array to hold the stack items. Rewrite the methods to fit this new representation and write a program that demonstrates all the methods, including the copy constructor and assignment operator.
Code - prototypes
// stack.h -- class definition for the stack ADT
#ifndef STACK_H_
#define STACK_H_
typedef unsigned long Item;
class Stack
{
private:
enum
{
MAX = 10
}; // constant specific to class
Item *pitems; // holds stack items
int size; // number of elements in stack
int top; // index for top stack item
public:
Stack(int n = MAX); // creates stack with n elements
Stack(const Stack &st);
~Stack();
bool isempty() const;
bool isfull() const;
// push() returns false if stack already is full, true otherwise
bool push(const Item &item); // add item to stack
// pop() returns false if stack already is empty, true otherwise
bool pop(Item &item); // pop top into item
Stack &operator=(const Stack &st);
};
#endif
Code - methods
// stack.cpp -- Stack member functions
#include "ch12_4_stack.h"
Stack::Stack(int n)
// create an empty stack
{
pitems = new Item[n]{};
size = n;
top = 0;
}
Stack::Stack(const Stack &st)
{
pitems = new Item[st.size]{};
for (int i = 0; i < st.size; i++)
pitems[i] = st.pitems[i];
size = st.size;
top = st.top;
}
Stack::~Stack(){
delete [] pitems;
}
bool Stack::isempty() const
{
return top == 0;
}
bool Stack::isfull() const
{
return top == MAX;
}
bool Stack::push(const Item &item)
{
if (top < MAX)
{
Item *newPitems = new Item[++size]{};
for (int i = 0; i < (size - 1); i++)
newPitems[i] = pitems[i];
delete[] pitems;
pitems = newPitems;
pitems[top++] = item;
return true;
}
else
return false;
}
bool Stack::pop(Item &item)
{
if (top > 0)
{
Item *newPitems = new Item[--size]{};
for (int i = 0; i < size; i++)
newPitems[i] = pitems[i];
delete[] pitems;
pitems = newPitems;
item = pitems[--top];
return true;
}
else
return false;
}
Stack &Stack::operator=(const Stack &st)
{
pitems = new Item[st.size]{};
for (int i = 0; i < st.size; i++)
pitems[i] = st.pitems[i];
size = st.size;
top = st.top;
return *this;
}
Code - program
// stacker.cpp -- testing the Stack class
#include <iostream>
#include <cctype> // or ctype.h
#include "ch12_4_stack.h"
int main()
{
using namespace std;
Stack st; // create an empty stack
char ch;
unsigned long po;
cout << "Please enter A to add a purchase order,\n"
<< "P to process a PO, or Q to quit.\n";
while (cin >> ch && toupper(ch) != 'Q')
{
while (cin.get() != '\n')
continue;
if (!isalpha(ch))
{
cout << '\a';
continue;
}
switch (ch)
{
case 'A':
case 'a':
cout << "Enter a PO number to add: ";
cin >> po;
if (st.isfull())
cout << "stack already full\n";
else
st.push(po);
break;
case 'P':
case 'p':
if (st.isempty())
cout << "stack already empty\n";
else
{
st.pop(po);
cout << "PO #" << po << " popped\n";
}
break;
}
cout << "Please enter A to add a purchase order,\n"
<< "P to process a PO, or Q to quit.\n";
}
cout << "Bye\n";
return 0;
}
/*
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
A
Enter a PO number to add: 17885
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
PO #17885 popped
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
A
Enter a PO number to add: 17965
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
A
Enter a PO number to add: 18002
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
PO #18002 popped
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
PO #17965 popped
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
stack already empty
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
Q
Bye
*/
5 - The Bank of Heather has performed a study showing that ATM customers won’t wait more than one minute in line. Using the simulation from Listing 12.10 (queue.h), find a value for number of customers per hour that leads to an average wait time of one minute. (Use at least a 100-hour trial period.)
Code - prototypes
#ifndef QUEUE_H_
#define QUEUE_H_
// This queue will contain Customer items
class Customer
{
private:
long arrive; // arrival time for customer
int processtime; // processing time for customer
public:
Customer() { arrive = processtime = 0; }
void set(long when);
long when() const { return arrive; }
int ptime() const { return processtime; }
};
typedef Customer Item;
class Queue
{
private:
// class scope definitions
// Node is a nested structure definition local to this class
struct Node
{
Item item;
struct Node *next;
};
enum
{
Q_SIZE = 10
};
// private class members
Node *front; // pointer to front of Queue
Node *rear; // pointer to rear of Queue
int items; // current number of items in Queue
const int qsize; // maximum number of items in Queue
// preemptive definitions to prevent public copying
Queue(const Queue &q) : qsize(0) {}
Queue &operator=(const Queue &q) { return *this; }
public:
Queue(int qs = Q_SIZE); // create queue with a qs limit
~Queue();
bool isempty() const;
bool isfull() const;
int queuecount() const;
bool enqueue(const Item &item); // add item to end
bool dequeue(Item &item); // remove item from front
};
#endif
Code - methods
// queue.cpp -- Queue and Customer methods
#include "ch12_5_queue.h"
#include <cstdlib>
// (or stdlib.h) for rand()
// Queue methods
Queue::Queue(int qs) : qsize(qs)
{
front = rear = NULL; // or nullptr
items = 0;
}
Queue::~Queue()
{
Node *temp;
while (front != NULL) // while queue is not yet empty
{
temp = front; // save address of front item
front = front->next; // reset pointer to next item
delete temp; // delete former front
}
}
bool Queue::isempty() const
{
return items == 0;
}
bool Queue::isfull() const
{
return items == qsize;
}
int Queue::queuecount() const
{
return items;
}
// Add item to queue
bool Queue::enqueue(const Item &item)
{
if (isfull())
return false;
Node *add = new Node; // create node
// on failure, new throws std::bad_alloc exception
add->item = item; // set node pointers
add->next = NULL; // or nullptr;
items++;
if (front == NULL) // if queue is empty,
front = add; // place item at front
else
rear->next = add; // else place at rear
rear = add; // have rear point to new node
return true;
}
// Place front item into item variable and remove from queue
bool Queue::dequeue(Item &item)
{
if (front == NULL)
return false;
item = front->item; // set item to first item in queue
items--;
Node *temp = front; // save location of first item
front = front->next; // reset front to next item
delete temp; // delete former first item
if (items == 0)
rear = NULL;
return true;
}
// customer method
// when is the time at which the customer arrives
// the arrival time is set to when and the processing
// time set to a random value in the range 1 - 3
void Customer::set(long when)
{
processtime = std::rand() % 3 + 1;
arrive = when;
}
Code - program
// bank.cpp -- using the Queue interface
#include <iostream>
#include <cstdlib> // for rand() and srand()
#include <ctime> // for time()
#include "ch12_5_queue.h"
const int MIN_PER_HR = 60;
bool newcustomer(double x); // is there a new customer?
double simulation(int qs, int hours, double perhour);
int main()
{
// hard-coded data for simulation
int qs = 150; // rand() % 100 + 1; // size of queue 1 - 100
int hours = 1000; // hours of simulation
double perhour = 10000; // rand() % 10 + 1; // average # of arrival per hour
double avgWait{};
do
{
avgWait = simulation(qs, hours, perhour--);
}
while(avgWait > 1);
std::cout << "\nNumber of customers per hour that leads"
<< " to an average wait time of one minute : "
<< perhour << "\n"
<< "for queue size: " << qs << "; and " << hours << " hours of simulation";
std::cout << "Done!\n";
return 0;
}
double simulation(int qs, int hours, double perhour)
{
using std::cin;
using std::cout;
using std::endl;
Item temp; // new customer data
long turnaways = 0; // turned away by full queue
long customers = 0; // joined the queue
long served = 0; // served during the simulation
long sum_line = 0; // cumulative line length
int wait_time = 0; // time until autoteller is free
long line_wait = 0; // cumulative time in line
// setting things up
using std::ios_base;
std::srand(std::time(0)); // random initializing of rand()
cout << "Case Study: Bank of Heather Automatic Teller\n";
// cout << "Enter maximum size of queue: ";
// value in the range 1 - 100
// qs = rand() % 100 + 1; // cin >> qs;
cout << "; Max queue for simulation: " << qs;
Queue line(qs); // line queue holds up to qs people
// cout << "Enter the number of simulation hours: ";
// hours of simulation // cin >> hours; // simulation will run 1 cycle per minute
cout << "; Simulation hours: " << hours;
long cyclelimit = MIN_PER_HR * hours; // # of cycles
// cout << "Enter the average number of customers per hour: ";
cout << "; Average number of customers per hour: " << perhour << " ";
// cin >> perhour;
double min_per_cust; // average time between arrivals
min_per_cust = MIN_PER_HR / perhour;
// running the simulation
for (int cycle = 0; cycle < cyclelimit; cycle++)
{
if (newcustomer(min_per_cust)) // have newcomer
{
if (line.isfull())
turnaways++;
else
{
customers++;
temp.set(cycle);
// cycle = time of arrival
line.enqueue(temp); // add newcomer to line
}
}
if (wait_time <= 0 && !line.isempty())
{
line.dequeue(temp); // attend next customer
wait_time = temp.ptime(); // for wait_time minutes
line_wait += cycle - temp.when();
served++;
}
if (wait_time > 0)
wait_time--;
sum_line += line.queuecount();
}
// reporting results
if (customers > 0)
{
cout << "customers accepted: " << customers << endl;
cout << " customers served: " << served << endl;
cout << "turnaways : " << turnaways << endl;
cout << "average queue size: ";
cout.precision(2);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << (double)sum_line / cyclelimit << endl;
cout << " average wait time: "
<< (double)line_wait / served << " minutes\n";
}
else
cout << "No customers!\n";
return (double)line_wait / served;
}
// x = average time, in minutes, between customers
// return value is true if customer shows up this minute
bool newcustomer(double x)
{
return (std::rand() * x / RAND_MAX < 1);
}
/*
⋮
; Max queue for simulation: 150; Simulation hours: 1000; Average number of customers per hour: 18.00 customers accepted: 18151
customers served: 18151
turnaways : 0
average queue size: 0.31
average wait time: 1.03 minutes
Case Study: Bank of Heather Automatic Teller
; Max queue for simulation: 150; Simulation hours: 1000; Average number of customers per hour: 17.00 customers accepted: 17100
customers served: 17099
turnaways : 0
average queue size: 0.25
average wait time: 0.88 minutes
Number of customers per hour that leads to an average wait time of one minute : 16.00
Done!
*/
6 - The Bank of Heather would like to know what would happen if it added a second ATM. Modify the simulation in this chapter so that it has two queues. Assume that a customer will join the first queue if it has fewer people in it than the second queue and that the customer will join the second queue otherwise. Again, find a value for number of customers per hour that leads to an average wait time of one minute. (Note:This is a nonlinear problem in that doubling the number of ATMs doesn’t double the number of customers who can be handled per hour with a oneminute wait maximum.)
Code - program
// bank.cpp -- using the Queue interface
#include <iostream>
#include <cstdlib> // for rand() and srand()
#include <ctime> // for time()
#include "ch12_5_queue.h"
const int MIN_PER_HR = 60;
bool newcustomer(double x); // is there a new customer?
double simulation(int qs, int hours, double perhour);
int main()
{
// hard-coded data for simulation
int qs = 150; // rand() % 100 + 1; // size of queue 1 - 100
int hours = 1000; // hours of simulation
double perhour = 10000; // rand() % 10 + 1; // average # of arrival per hour
double avgWait{};
do
{
avgWait = simulation(qs, hours, perhour--);
} while (avgWait > 1);
std::cout << "\nNumber of customers per hour that leads"
<< " to an average wait time of one minute : "
<< perhour << "\n"
<< "for queue size: " << qs << "; and " << hours << " hours of simulation";
std::cout << "\n\nDone!\n";
return 0;
}
double simulation(int qs, int hours, double perhour)
{
using std::cin;
using std::cout;
using std::endl;
Item temp; // new customer data
long turnaways = 0; // turned away by full queue
long customers = 0; // joined the queue
long served = 0; // served during the simulation
long sum_line = 0; // cumulative line length
int wait_time[2]{}; // time until autoteller is free
long line_wait = 0; // cumulative time in line
// setting things up
using std::ios_base;
std::srand(std::time(0)); // random initializing of rand()
cout << "Case Study: Bank of Heather Automatic Teller\n";
// cout << "Enter maximum size of queue: ";
// value in the range 1 - 100
// qs = rand() % 100 + 1; // cin >> qs;
cout << "; Max queue for simulation: " << qs;
Queue line[2]{qs, qs}; // line queue holds up to qs people
// cout << "Enter the number of simulation hours: ";
// hours of simulation // cin >> hours; // simulation will run 1 cycle per minute
cout << "; Simulation hours: " << hours;
long cyclelimit = MIN_PER_HR * hours; // # of cycles
// cout << "Enter the average number of customers per hour: ";
cout << "; Average number of customers per hour: " << perhour << " ";
// cin >> perhour;
double min_per_cust; // average time between arrivals
min_per_cust = MIN_PER_HR / perhour;
// running the simulation
for (int cycle = 0; cycle < cyclelimit; cycle++)
{
if (newcustomer(min_per_cust)) // have newcomer
{
if (line[0].queuecount() > line[1].queuecount())
{
if (line[1].isfull())
turnaways++;
else
{
customers++;
temp.set(cycle);
// cycle = time of arrival
line[1].enqueue(temp); // add newcomer to line
}
}
else
{
if (line[0].isfull())
turnaways++;
else
{
customers++;
temp.set(cycle);
// cycle = time of arrival
line[0].enqueue(temp); // add newcomer to line
}
}
}
if (wait_time[0] <= 0 && !line[0].isempty())
{
line[0].dequeue(temp); // attend next customer
wait_time[0] = temp.ptime(); // for wait_time minutes
line_wait += cycle - temp.when();
served++;
}
if (wait_time[1] <= 0 && !line[1].isempty())
{
line[1].dequeue(temp); // attend next customer
wait_time[1] = temp.ptime(); // for wait_time minutes
line_wait += cycle - temp.when();
served++;
}
if (wait_time[0] > 0)
wait_time[0]--;
if (wait_time[1] > 0)
wait_time[1]--;
sum_line += line[0].queuecount();
sum_line += line[1].queuecount();
}
// reporting results
if (customers > 0)
{
cout << "customers accepted: " << customers << endl;
cout << " customers served: " << served << endl;
cout << "turnaways : " << turnaways << endl;
cout << "average queue size: ";
cout.precision(2);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << (double)sum_line / cyclelimit << endl;
cout << " average wait time: "
<< (double)line_wait / served << " minutes\n";
}
else
cout << "No customers!\n";
return (double)line_wait / served;
}
// x = average time, in minutes, between customers
// return value is true if customer shows up this minute
bool newcustomer(double x)
{
return (std::rand() * x / RAND_MAX < 1);
}
Chapter 13
1 - Start with the following class declaration:
// base class
class Cd
{ // represents a CD disk
private:
char performers[50];
char label[20];
int selections; // number of selections
double playtime; // playing time in minutes
public:
Cd(char *s1, char *s2, int n, double x);
Cd(const Cd &d);
Cd();
~Cd();
void Report() const; // reports all CD data
Cd &operator=(const Cd &d);
};
Derive a Classic class that adds an array of char members that will hold a string
identifying the primary work on the CD. If the base class requires that any functions
be virtual, modify the base-class declaration to make it so. If a declared
method is not needed, remove it from the definition. Test your product with the
following program:
#include <iostream>
using namespace std;
#include "classic.h" // which will contain #include cd.h
void Bravo(const Cd &disk);
int main()
{
Cd c1("Beatles", "Capitol", 14, 35.5);
Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C",
"Alfred Brendel", "Philips", 2, 57.17);
Cd *pcd = &c1;
cout << "Using object directly:\n";
c1.Report(); // use Cd method
c2.Report(); // use Classic method
cout << "Using type cd * pointer to objects:\n";
pcd->Report(); // use Cd method for cd object
pcd = &c2;
pcd->Report(); // use Classic method for classic object
cout << "Calling a function with a Cd reference argument:\n";
Bravo(c1);
Bravo(c2);
cout << "Testing assignment: ";
Classic copy;
copy = c2;
copy.Report();
return 0;
}
void Bravo(const Cd &disk)
{
disk.Report();
}
Code - CD base class prototypes
#ifndef _CD_H_
#define _CD_H_
#include <iostream>
#include <cstring>
// base class
class Cd
{ // represents a CD disk
private:
char performers[50];
char label[20];
int selections; // number of selections
double playtime; // playing time in minutes
public:
Cd(const char *s1,const char *s2, int n, double x);
Cd(const Cd &d);
Cd(); // needed - Classic()
// ~Cd(); // not needed - lack of dynamic memory allocation in both (thus default is ok)
virtual void Report() const; // reports all CD data
Cd &operator=(const Cd &d);
};
#endif
Code - CD methods
#include "ch13_1_cd.h"
Cd::Cd(const char *s1, const char *s2, int n, double x)
{
strcpy(performers, s1);
strcpy(label, s2);
selections = n;
playtime = x;
}
Cd::Cd(const Cd &d)
{
strcpy(performers, d.performers);
strcpy(label, d.label);
selections = d.selections;
playtime = d.playtime;
}
Cd::Cd()
{
performers[0] = '\0';
label[0] = '\0';
selections = 0;
playtime = 0;
}
void Cd::Report() const
{
std::cout << "\n Performance by: " << performers
<< "\n Album: " << label
<< "\n Number of selections: " << selections
<< "\n Playtime: " << playtime << "\n";
}
Cd &Cd::operator=(const Cd &d)
{
if (this == &d)
return *this;
strcpy(performers, d.performers);
strcpy(label, d.label);
selections = d.selections;
playtime = d.playtime;
return *this;
}
Code - Classic derived class prototypes
// Derive a <code>Classic</code> class that adds an array of <code>char</code> members that will hold a string
// identifying the primary work on the `CD`.
#include "ch13_1_cd.h"
class Classic : public Cd {
private:
char primaryWork[100];
public:
Classic(const char *pw,const char *pd,const char *lb, int n, double x);
Classic(const Classic &d);
Classic(); // needed - line 29
// ~Classic(); // not needed - lack of dynamic memory allocation in both (thus default is ok)
virtual void Report() const; // reports all Classic data
Classic &operator=(const Classic &d);
};
Code - Classic methods
#include "ch13_1_classic.h"
Classic::Classic(const char *pw,const char *pf,const char *lb, int n, double x)
: Cd(pf, lb, n, x)
{
strcpy(primaryWork, pw);
}
Classic::Classic(const Classic &d)
: Cd(d)
{
strcpy(primaryWork, d.primaryWork);
}
Classic::Classic()
: Cd()
{
primaryWork[0] = '\0';
}
void Classic::Report() const
{
Cd::Report();
std::cout <<
"\n Primary work: " << primaryWork <<
"\n";
}
Classic &Classic::operator=(const Classic &d)
{
if(this == &d)
return *this;
Cd::operator=(d);
strcpy(primaryWork, d.primaryWork);
return *this;
}
Code - program
#include <iostream>
using namespace std;
#include "ch13_1_classic.h" // which will contain #include cd.h
void Bravo(const Cd &disk);
int main()
{
{
Cd c1("Beatles", "Capitol", 14, 35.5);
Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C",
"Alfred Brendel", "Philips", 2, 57.17);
Cd *pcd = &c1;
cout << "Using object directly:\n";
c1.Report(); // use Cd method
c2.Report(); // use Classic method
cout << "Using type cd * pointer to objects:\n";
pcd->Report(); // use Cd method for cd object
pcd = &c2;
pcd->Report(); // use Classic method for classic object
cout << "Calling a function with a Cd reference argument:\n";
Bravo(c1);
Bravo(c2);
cout << "Testing assignment: ";
Classic copy;
copy = c2;
copy.Report();
}
return 0;
}
void Bravo(const Cd &disk)
{
disk.Report();
}
2 - Do Programming Exercise 1 but use dynamic memory allocation instead of fixedsize arrays for the various strings tracked by the two classes.
Code - CD base class prototypes
#ifndef _CD_H_
#define _CD_H_
#include <iostream>
#include <cstring>
// base class
class Cd
{ // represents a CD disk
private:
char *performers;
char *label;
int selections; // number of selections
double playtime; // playing time in minutes
public:
Cd(const char *s1, const char *s2, int n, double x);
Cd(const Cd &d);
Cd(); // needed - Classic()
virtual ~Cd(); // needed - dynamic memory allocation
virtual void Report() const; // reports all CD data
virtual Cd &operator=(const Cd &d);
};
#endif
Code - CD methods
#include "ch13_2_cd.h"
Cd::Cd(const char *s1,const char *s2, int n, double x)
{
performers = new char[strlen(s1) + 1];
strcpy(performers, s1);
label = new char[strlen(s2) + 1];
strcpy(label, s2);
selections = n;
playtime = x;
}
Cd::Cd(const Cd &d){
performers = new char[strlen(d.performers) + 1];
strcpy(performers, d.performers);
label = new char[strlen(d.label) + 1];
strcpy(label, d.label);
selections = d.selections;
playtime = d.playtime;
}
Cd::Cd()
{
performers = new char[1];
performers[0] = '\0';
label = new char[1];
label[0] = '\0';
selections = 0;
playtime = 0;
}
Cd::~Cd()
{
std::cout << "\nper delete: " << performers;
std::cout << "\nlbl delete: " << label;
delete [] performers;
delete [] label;
}
void Cd::Report() const
{
std::cout <<
"\n Performance by: " << performers <<
"\n Album: " << label <<
"\n Number of selections: " << selections <<
"\n Playtime: " << playtime <<
"\n";
}
Cd &Cd::operator=(const Cd &d)
{
if(this == &d)
return *this;
delete [] performers;
performers = new char[strlen(d.performers) + 1];
strcpy(performers, d.performers);
delete [] label;
label = new char[strlen(d.label) + 1];
strcpy(label, d.label);
selections = d.selections;
playtime = d.playtime;
return *this;
}
Code - Classic derived class prototypes
// Derive a <code>Classic</code> class that adds an array of <code>char</code> members that will hold a string
// identifying the primary work on the `CD`.
#include "ch13_2_cd.h"
class Classic : public Cd
{
private:
char *primaryWork;
public:
Classic(const char *pw, const char *pd, const char *lb, int n, double x);
Classic(const Classic &d);
Classic(); // needed - line 29
virtual ~Classic(); // needed - dynamic memory allocation
virtual void Report() const; // reports all Classic data
virtual Classic &operator=(const Classic &d);
};
Code - Classic methods
#include "ch13_2_classic.h"
Classic::Classic(const char *pw,const char *pf,const char *lb, int n, double x)
: Cd(pf, lb, n, x)
{
primaryWork = new char[strlen(pw) + 1];
strcpy(primaryWork, pw);
}
Classic::Classic(const Classic &d)
: Cd(d)
{
primaryWork = new char[strlen(d.primaryWork) + 1];
strcpy(primaryWork, d.primaryWork);
}
Classic::Classic()
: Cd()
{
primaryWork = new char[1];
primaryWork[0] = '\0';
}
Classic::~Classic()
{
std::cout << "\nprw delete: " << primaryWork;
delete [] primaryWork;
}
void Classic::Report() const
{
Cd::Report();
std::cout <<
"\n Primary work: " << primaryWork <<
"\n";
}
Classic &Classic::operator=(const Classic &d)
{
if(this == &d)
return *this;
Cd::operator=(d);
delete [] primaryWork;
primaryWork = new char[strlen(d.primaryWork) + 1];
strcpy(primaryWork, d.primaryWork);
return *this;
}
Code - program
#include <iostream>
using namespace std;
#include "ch13_2_classic.h" // which will contain #include cd.h
void Bravo(const Cd &disk);
int main()
{
{
Cd c1("Beatles", "Capitol", 14, 35.5);
Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C",
"Alfred Brendel", "Philips", 2, 57.17);
Cd *pcd = &c1;
cout << "Using object directly:\n";
c1.Report(); // use Cd method
c2.Report(); // use Classic method
cout << "Using type cd * pointer to objects:\n";
pcd->Report(); // use Cd method for cd object
pcd = &c2;
pcd->Report(); // use Classic method for classic object
cout << "Calling a function with a Cd reference argument:\n";
Bravo(c1);
Bravo(c2);
cout << "Testing assignment: ";
Classic copy;
copy = c2;
copy.Report();
}
return 0;
}
void Bravo(const Cd &disk)
{
disk.Report();
}
3 -
Revise the baseDMA-lacksDMA-hasDMA class hierarchy so that all three classes are
derived from an ABC. Test the result with a program similar to the one in Listing
13.10 (usebrass2.cpp). That is, it should feature an array of pointers to the ABC and allow the user
to make runtime decisions as to what types of objects are created. Add virtual
View() methods to the class definitions to handle displaying the data.
Code - classes prototypes
// dma.h -- inheritance and dynamic memory allocation
#ifndef DMA_H_
#define DMA_H_
#include <iostream>
#include <cstring>
#include <string>
// ABC (Abstract Base Class) class
class absDMA
{
protected:
char *label;
int rating;
public:
absDMA(const std::string &l = "null", int r = 0);
absDMA(const char *l = "null", int r = 0);
absDMA(const absDMA &ab);
virtual void View() = 0; // pure virtual function
virtual ~absDMA();
};
// Base Class Using DMA - can be deleted and changed into absDMA
// (left only for sake of double inheritance)
class baseDMA : public absDMA
{
public:
baseDMA(const std::string &l = "null", int r = 0) : absDMA(l, r) {};
baseDMA(const char *l = "null", int r = 0) : absDMA(l, r) {};
baseDMA(const baseDMA &rs) : absDMA(rs) {};
baseDMA &operator=(const baseDMA &rs);
friend std::ostream &operator<<(std::ostream &os,
const baseDMA &rs);
};
// derived class without DMA
// no destructor needed
// uses implicit copy constructor
// uses implicit assignment operator
class lacksDMA : public baseDMA
{
private:
enum
{
COL_LEN = 40
};
char color[COL_LEN];
public:
lacksDMA(const std::string &c = "blank", const std::string &l = "null",
int r = 0);
lacksDMA(const char *c = "blank", const char *l = "null",
int r = 0);
lacksDMA(const char *c, const baseDMA &rs);
virtual void View();
friend std::ostream &operator<<(std::ostream &os,
const lacksDMA &rs);
};
// derived class with DMA
class hasDMA : public baseDMA
{
private:
char *style;
public:
hasDMA(const std::string &s = "none", const std::string &l = "null",
int r = 0);
hasDMA(const char *s = "none", const char *l = "null",
int r = 0);
hasDMA(const char *s, const baseDMA &rs);
hasDMA(const hasDMA &hs);
~hasDMA();
virtual void View();
hasDMA &operator=(const hasDMA &rs);
friend std::ostream &operator<<(std::ostream &os,
const hasDMA &rs);
};
#endif
Code - classes methods
// dma.cpp --dma class methods
#include "ch13_3_dma.h"
// absDMA methods
void absDMA::View()
{
std::cout << "Label: " << label << std::endl;
std::cout << "Rating: " << rating << std::endl;
}
absDMA::absDMA(const std::string &l, int r)
{
label = new char[l.length() + 1];
l.copy(label, l.length());
label[l.length()] = '\0';
rating = r;
}
absDMA::absDMA(const char *l, int r)
{
label = new char[std::strlen(l) + 1];
std::strcpy(label, l);
label[std::strlen(l)] = '\0';
rating = r;
}
absDMA::absDMA(const absDMA &ab)
{
label = new char[std::strlen(ab.label) + 1];
std::strcpy(label, ab.label);
label[std::strlen(ab.label)] = '\0'; // without it, there will be printed trash at the end
rating = ab.rating;
}
absDMA::~absDMA()
{
delete[] label;
}
// baseDMA methods
baseDMA &baseDMA::operator=(const baseDMA &rs)
{
if (this == &rs)
return *this;
delete[] label;
label = new char[std::strlen(rs.label) + 1];
std::strcpy(label, rs.label);
rating = rs.rating;
return *this;
}
std::ostream &operator<<(std::ostream &os, const baseDMA &rs)
{
os << "Label: " << rs.label << std::endl;
os << "Rating: " << rs.rating << std::endl;
return os;
}
// lacksDMA methods
void lacksDMA::View()
{
std::cout << "Label: " << label << std::endl;
std::cout << "Rating: " << rating << std::endl;
std::cout << "Color: " << color << std::endl;
}
lacksDMA::lacksDMA(const std::string &c, const std::string &l, int r)
: baseDMA(l, r)
{
c.copy(color, c.length());
color[c.length()] = '\0';
}
lacksDMA::lacksDMA(const char *c, const char *l, int r)
: baseDMA(l, r)
{
std::strncpy(color, c, COL_LEN - 1);
color[COL_LEN - 1] = '\0';
}
lacksDMA::lacksDMA(const char *c, const baseDMA &rs)
: baseDMA(rs)
{
std::strncpy(color, c, COL_LEN - 1);
color[COL_LEN - 1] = '\0';
}
std::ostream &operator<<(std::ostream &os, const lacksDMA &ls)
{
os << (const baseDMA &)ls;
os << "Color: " << ls.color << std::endl;
return os;
}
// hasDMA methods
void hasDMA::View()
{
std::cout << "Label: " << label << std::endl;
std::cout << "Rating: " << rating << std::endl;
std::cout << "Style: " << style << std::endl;
}
hasDMA::hasDMA(const std::string &s, const std::string &l, int r)
: baseDMA(l, r)
{
style = new char[s.length() + 1];
s.copy(style, s.length());
style[s.length()] = '\0';
}
hasDMA::hasDMA(const char *s, const char *l, int r)
: baseDMA(l, r)
{
style = new char[std::strlen(s) + 1];
std::strcpy(style, s);
style[std::strlen(s)] = '\0';
}
hasDMA::hasDMA(const char *s, const baseDMA &rs)
: baseDMA(rs)
{
style = new char[std::strlen(s) + 1];
std::strcpy(style, s);
}
hasDMA::hasDMA(const hasDMA &hs)
: baseDMA(hs) // invoke base class copy constructor
{
style = new char[std::strlen(hs.style) + 1];
std::strcpy(style, hs.style);
}
hasDMA::~hasDMA()
{
delete[] style;
}
hasDMA &hasDMA::operator=(const hasDMA &hs)
{
if (this == &hs)
return *this;
baseDMA::operator=(hs); // copy base portion
delete[] style; // prepare for new style
style = new char[std::strlen(hs.style) + 1];
std::strcpy(style, hs.style);
style[std::strlen(hs.style)] = '\0';
return *this;
}
std::ostream &operator<<(std::ostream &os, const hasDMA &hs)
{
os << (const baseDMA &)hs;
os << "Style: " << hs.style << std::endl;
return os;
}
Code - program
// usebrass2.cpp -- polymorphic example - modified for exercise
// compile with brass.cpp
#include <iostream>
#include <string>
#include "ch13_3_dma.h"
const int ALBUMS = 2;
int main()
{
using std::cin;
using std::cout;
using std::endl;
baseDMA *p_albums[ALBUMS];
std::string tmp_lbl, temp_color;
long tmp_rtg;
char kind;
for (int i = 0; i < ALBUMS; i++)
{
cout << "Enter name of " << i + 1 << " music album: ";
getline(cin, tmp_lbl);
cout << "Enter rating of the album: ";
cin >> tmp_rtg;
cout << "Enter 1 for baseDMA (Album with Dynamic Music Arrangement filter) album or "
<< "2 for lacksDMA (Album without Dynamic Music Arrangement filter) album : ";
while (cin >> kind && (kind != '1' && kind != '2'))
cout << "Enter either 1 or 2: ";
if (kind == '1')
{
cout << "Enter dominating color of the album: $";
cin >> temp_color;
p_albums[i] = new lacksDMA(temp_color, tmp_lbl, tmp_rtg);
}
else
{
std::string tmp_style;
cout << "Enter the style of " << i << " the album ";
cin >> tmp_style;
p_albums[i] = new hasDMA(tmp_style, tmp_lbl, tmp_rtg);
}
while (cin.get() != '\n')
continue;
}
cout << endl;
for (int i = 0; i < ALBUMS; i++)
{
p_albums[i]->View();
cout << endl;
}
for (int i = 0; i < ALBUMS; i++)
{
delete p_albums[i]; // free memory
}
cout << "Done.\n";
return 0;
}
4 -
The Benevolent Order of Programmers maintains a collection of bottled port.
To describe it, the BOP Portmaster has devised a Port class, as declared here:
#include <iostream>
using namespace std;
class Port
{
private:
char *brand;
char style[20]; // i.e., tawny, ruby, vintage
int bottles;
public:
Port(const char *br = "none", const char *st = "none", int b = 0);
Port(const Port &p); // copy constructor
virtual ~Port() { delete[] brand; }
Port &operator=(const Port &p);
Port &operator+=(int b); // adds b to bottles
Port &operator-=(int b); // subtracts b from bottles, if
available int BottleCount() const { return bottles; }
virtual void Show() const;
friend ostream &operator<<(ostream &os, const Port &p);
};
The Show() method presents information in the following format:
The operator<<() function presents information in the following format (with no
newline character at the end):
The Portmaster completed the method definitions for the Port class and then
derived the VintagePort class as follows before being relieved of his position for
accidentally routing a bottle of ’45 Cockburn to someone preparing an experimental
barbecue sauce:
class VintagePort : public Port // style necessarily = "vintage"
{
private:
char *nickname; // i.e., "The Noble" or "Old Velvet", etc.
int year; // vintage year
public:
VintagePort();
VintagePort(const char *br, int b, const char *nn, int y);
VintagePort(const VintagePort &vp);
~VintagePort() { delete[] nickname; }
VintagePort &operator=(const VintagePort &vp);
void Show() const;
friend ostream &operator<<(ostream &os, const VintagePort &vp);
};
You get the job of completing the VintagePort work.
A. Your first task is to re-create the Port method definitions because the former
Portmaster immolated his upon being relieved.
B. Your second task is to explain why certain methods are redefined and others are not.
C. Your third task is to explain why operator=() and operator<<() are not virtual.
D. Your fourth task is to provide definitions for the VintagePort methods.
Code - class prototypes - Port
#ifndef _PORT_H_
#define _PORT_H_
#include <iostream>
#include <cstring>
// base class
using namespace std;
class Port
{
private:
char *brand;
char style[20]; // i.e., tawny, ruby, vintage
int bottles;
public:
Port(const char *br = "none", const char *st = "none", int b = 0);
Port(const Port &p); // copy constructor
virtual ~Port() { delete[] brand; }
Port &operator=(const Port &p);
Port &operator+=(int b); // adds b to bottles
Port &operator-=(int b); // subtracts b from bottles, if available
int BottleCount() const { return bottles; }
virtual void Show() const;
friend ostream &operator<<(ostream &os, const Port &p);
};
#endif
Code - class methods - Port
// >>>>> A <<<<<
#include "ch13_4_port.h"
Port::Port(const char *br, const char *st, int b)
{
brand = new char[strlen(br) + 1];
strcpy(brand, br);
brand[strlen(br)] = '\0';
strcpy(style, st);
style[strlen(st)] = '\0';
bottles = b;
}
Port::Port(const Port &p) // copy constructor
{
brand = new char[strlen(p.brand) + 1];
strcpy(brand, p.brand);
brand[strlen(p.brand)] = '\0';
strcpy(style, p.style);
style[strlen(p.style)] = '\0';
bottles = p.bottles;
}
Port &Port::operator=(const Port &p)
{
if(this == &p)
return *this;
delete[] brand;
brand = new char[strlen(p.brand) + 1];
strcpy(brand, p.brand);
brand[strlen(p.brand)] = '\0';
strcpy(style, p.style);
style[strlen(p.style)] = '\0';
bottles = p.bottles;
return *this;
}
Port &Port::operator+=(int b) // adds b to bottles
{
this->bottles += b;
return *this;
}
Port &Port::operator-=(int b) // subtracts b from bottles, if available
{
this->bottles -= b;
return *this;
}
void Port::Show() const
{
cout << "Brand: " << brand << endl;
cout << "Kind: " << style << endl;
cout << "Bottles: " << bottles << endl;
}
ostream &operator<<(ostream &os, const Port &p)
{
os << p.brand << ", " << p.style << ", " << p.bottles;
return os;
}
Code - class prototypes - VintagePort
#ifndef _VPORT_H_
#define _VPORT_H_
#include "ch13_4_port.h"
// derived class
class VintagePort : public Port // style necessarily = "vintage"
{
private:
char *nickname; // i.e., "The Noble" or "Old Velvet", etc.
int year; // vintage year
public:
VintagePort();
VintagePort(const char *br, int b, const char *nn, int y);
VintagePort(const VintagePort &vp);
~VintagePort() { delete[] nickname; }
// >>>>> B <<<<<
// The rest of the methiods don't need to be redefined
// because there the same operations are used in both cases
VintagePort &operator=(const VintagePort &vp);
// virtual in the base class remains virtual in the derived class,
// even if the virtual keyword is omitted in the derived class
// The result is the same as if it would be vitrtual void Show() const below
void Show() const;
// >>>>> C <<<<<
// It is not virtual, because friend keyword
// cannot be combined with keyword virtual
friend ostream &operator<<(ostream &os, const VintagePort &vp);
};
#endif
Code - class methods - VintagePort
// >>>>> D <<<<<
#include "ch13_4_vport.h"
VintagePort::VintagePort()
: Port()
{
nickname = new char[1];
nickname[0] = '\0';
year = 0;
}
VintagePort::VintagePort(const char *br, int b, const char *nn, int y)
: Port(br, "none", b)
{
nickname = new char[strlen(nn) + 1];
strcpy(nickname, nn);
nickname[strlen(nn)] = '\0';
year = y;
}
VintagePort::VintagePort(const VintagePort &vp)
: Port(vp)
{
nickname = new char[strlen(vp.nickname) + 1];
strcpy(nickname, vp.nickname);
nickname[strlen(vp.nickname)] = '\0';
year = vp.year;
}
VintagePort &VintagePort::operator=(const VintagePort &vp)
{
if(this == &vp)
return *this;
Port::operator=(vp);
delete[] nickname;
nickname = new char[strlen(vp.nickname) + 1];
strcpy(nickname, vp.nickname);
nickname[strlen(vp.nickname)] = '\0';
year = vp.year;
return *this;
}
void VintagePort::Show() const
{
Port::Show();
cout << "Nickname: " << nickname << endl;
cout << "Year" << year << endl;
}
ostream &operator<<(ostream &os, const VintagePort &vp)
{
os << (const Port &)vp;
os << ", " << vp.nickname << ", " << vp.year;
return os;
}
Code - program
#include <iostream>
#include <string>
#include "ch13_4_vport.h"
const int BASES = 2;
int main(){
using std::cin;
using std::cout;
using std::endl;
Port *civBases[BASES];
VintagePort *civHist[BASES];
char *tmp_brand, *tmp_style;
char *tmp_nickname;
int bottles;
int years;
for (int i = 0; i < BASES; ++i)
{
cout << "\nEnter brand of " << i + 1 << " bottled port: ";
tmp_brand = new char[30];
cin.getline(tmp_brand, 30);
cout << "Enter type of the bottled port: ";
tmp_style = new char[30];
cin.getline(tmp_style, 30);
cout << "Enter number of bottles in " << tmp_brand << " port: ";
while (!(cin >> bottles))
{
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
civBases[i] = new Port(tmp_brand, tmp_style, bottles);
delete tmp_brand, tmp_style;
while (cin.get() != '\n')
continue;
}
for (int i = 0; i < BASES; ++i)
{
cout << "\nEnter brand of " << i + 1 << " historical bottled port: ";
tmp_brand = new char[30];
cin.getline(tmp_brand, 30);
cout << "Enter nickname of the historical bottled port: ";
tmp_nickname = new char[30];
cin.getline(tmp_nickname, 30);
cout << "Enter number of bottles in " << tmp_brand << " historical port: ";
while (!(cin >> bottles))
{
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
cout << "Enter founding year of " << tmp_brand << " historical port: ";
while (!(cin >> years))
{
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
civHist[i] = new VintagePort(tmp_brand, bottles, tmp_nickname, years);
delete tmp_brand, tmp_nickname;
while (cin.get() != '\n')
continue;
}
cout << endl;
cout << "Result : \n";
for (int i = 0; i < BASES; i++)
{
civBases[i]->Show();
cout << endl;
}
for (int i = 0; i < BASES; i++)
{
civHist[i]->Show();
cout << endl;
}
cout << "\nAssigning first two Ports as the same and display via << :\n";
*civBases[0] = *civBases[1];
*civHist[0] = *civHist[1];
for (int i = 0; i < BASES; i++)
{
cout << "Port " << i << ": " << *civBases[i];
cout << endl;
}
for (int i = 0; i < BASES; i++)
{
cout << "Historical port " << i << ": " << *civHist[i];
cout << endl;
}
cout << "\nDefault constructor:\n";
Port emptyPort;
VintagePort EmptyHPort;
cout << "Empty, default ports: \n";
cout << emptyPort << EmptyHPort;
for (int i = 0; i < BASES; i++)
{
delete civBases[i];
delete civHist[i];
}
cout << "Done.\n";
return 0;
}
Chapter 14
1 -
The Wine class has a string class object member (see Chapter 4) that holds the
name of a wine and a Pair object (as discussed in this chapter) of valarray
objects (as discussed in this chapter).The first member of each Pair object holds
the vintage years, and the second member holds the numbers of bottles owned for
the corresponding particular vintage year. For example, the first valarray object of
the Pair object might hold the years 1988, 1992, and 1996, and the second
valarray object might hold the bottle counts 24, 48, and 144. It may be convenient
for Wine to have an int member that stores the number of years. Also some
typedefs might be useful to simplify the coding:
Thus, the PairArray type represents type Pair<std::valarray. Implement the Wine class by using containment. The class
should have a default constructor and at least the following constructors:
// initialize label to l, number of years to y,
// vintage years to yr[], bottles to bot[]
Wine(const char * l, int y, const int yr[], const int bot[]);
// initialize label to l, number of years to y,
// create array objects of length y
Wine(const char * l, int y);
The Wine class should have a method GetBottles() that, given a Wine object with
y years, prompts the user to enter the corresponding number of vintage years and
bottle counts. A method Label() should return a reference to the wine name.
A method sum() should return the total number of bottles in the second
valarray object in the Pair object.
The program should prompt the user to enter a wine name, the number of elements
of the array, and the year and bottle count information for each array element.
The program should use this data to construct a Wine object and then display
the information stored in the object. For guidance, here’s a sample test program:
// pe14-1.cpp -- using Wine class with containment
#include <iostream>
#include "winec.h"
int main(void)
{
using std::cin;
using std::cout;
using std::endl;
cout << "Enter name of wine: ";
char lab[50];
cin.getline(lab, 50);
cout << "Enter number of years: ";
int yrs;
cin >> yrs;
Wine holding(lab, yrs); // store label, years, give arrays yrs elements
holding.GetBottles(); // solicit input for year, bottle count
holding.Show(); // display object contents
const int YRS = 3;
int y[YRS] = {1993, 1995, 1998};
int b[YRS] = {48, 60, 72};
// create new object, initialize using data in arrays y and b
Wine more("Gushing Grape Red", YRS, y, b);
more.Show();
cout << "Total bottles for " << more.Label() // use Label() method
<< ": " << more.sum() << endl; // use sum() method
cout << "Bye\n";
return 0;
}
And here’s some sample output:
Enter name of wine: Gully Wash
Enter number of years: 4
Enter Gully Wash data for 4 year(s):
Enter year: 1988
Enter bottles for that year: 42
Enter year: 1994
Enter bottles for that year: 58
Enter year: 1998
Enter bottles for that year: 122
Enter year: 2001
Enter bottles for that year: 144
Wine: Gully Wash
Year Bottles
1988 42
1994 58
1998 122
2001 144
Wine: Gushing Grape Red
Year Bottles
1993 48
1995 60
1998 72
Total bottles for Gushing Grape Red: 180
Bye
Code - classes prototypes
#include <iostream>
#include <string>
#include <valarray>
#ifndef _WINE_H_
#define _WINE_H_
class Wine
{
private:
typedef std::valarray<int> ArrayInt;
typedef std::pair<ArrayInt, ArrayInt> PairArray;
std::string s_Name;
PairArray pa_Data; // Pair <vintage years, bootles>
public:
// default constructor
Wine();
// initialize label to l, number of years to y,
// vintage years to yr[], bottles to bot[]
Wine(const char *l, int y, const int yr[], const int bot[]);
// initialize label to l, number of years to y,
// create array objects of length y
Wine(const char *l, int y);
~Wine();
void GetBottles();
void Show();
const std::string &Label();
int sum();
};
#endif
Code - classes methods
#include "ch14_1_wine.h"
/// Constructors ///
Wine::Wine()
{
s_Name = "";
}
Wine::Wine(const char *l, int y)
{
s_Name = l;
pa_Data.first.resize(y);
pa_Data.second.resize(y);
}
Wine::Wine(const char *l, int y, const int yr[], const int bot[])
{
s_Name = l;
pa_Data.first.resize(y);
pa_Data.second.resize(y);
for (int i{}; i < y; i++)
{
pa_Data.first[i] = yr[i];
pa_Data.second[i] = bot[i];
}
}
/// Destructors ///
Wine::~Wine()
{
}
/// Methods ///
void Wine::GetBottles()
{
std::cout << "Enter " << s_Name << " data for "
<< pa_Data.first.size() << " year(s): " << std::endl;
for (int i = 0; i < pa_Data.first.size(); ++i)
{
std::cout << "Enter year: ";
std::cin >> pa_Data.first[i];
std::cout << "Enter bootles for that year: ";
std::cin >> pa_Data.second[i];
}
}
const std::string &Wine::Label()
{
return s_Name;
}
void Wine::Show()
{
std::cout << "Wine: " << s_Name << std::endl;
std::cout << "Year Bottles" << std::endl;
for (int i = 0; i < pa_Data.first.size(); ++i)
{
std::cout << pa_Data.first[i] << " ";
std::cout << pa_Data.second[i] << std::endl;
}
}
int Wine::sum()
{
int _sum{};
for (int i = 0; i < pa_Data.first.size(); ++i)
{
_sum += pa_Data.second[i];
}
return _sum;
}
Code - program
// pe14-1.cpp -- using Wine class with containment
#include <iostream>
#include "ch14_1_wine.h"
int main(void)
{
using std::cin;
using std::cout;
using std::endl;
cout << "Enter name of wine: ";
char lab[50];
cin.getline(lab, 50);
cout << "Enter number of years: ";
int yrs;
cin >> yrs;
Wine holding(lab, yrs); // store label, years, give arrays yrs elements
holding.GetBottles(); // solicit input for year, bottle count
holding.Show(); // display object contents
const int YRS = 3;
int y[YRS] = {1993, 1995, 1998};
int b[YRS] = {48, 60, 72};
// create new object, initialize using data in arrays y and b
Wine more("Gushing Grape Red", YRS, y, b);
more.Show();
cout << "Total bottles for " << more.Label() // use Label() method
<< ": " << more.sum() << endl; // use sum() method
cout << "Bye\n";
return 0;
}
/*
And here’s some sample of expected output:
Enter name of wine: Gully Wash
Enter number of years: 4
Enter Gully Wash data for 4 year(s):
Enter year: 1988
Enter bottles for that year: 42
Enter year: 1994
Enter bottles for that year: 58
Enter year: 1998
Enter bottles for that year: 122
Enter year: 2001
Enter bottles for that year: 144
Wine: Gully Wash
Year Bottles
1988 42
1994 58
1998 122
2001 144
Wine: Gushing Grape Red
Year Bottles
1993 48
1995 60
1998 72
Total bottles for Gushing Grape Red: 180
Bye
*/
2 -
This exercise is the same as Programming Exercise 1, except that you should use private
inheritance instead of containment. Again, a few typedefs might prove handy.
Also you might contemplate the meaning of statements such as the following:
The class should work with the same test program as shown in Programming Exercise 1.
Code - classes prototypes
#include <iostream>
#include <string>
#include <valarray>
#ifndef _WINE_H_
#define _WINE_H_
typedef std::valarray<int> ArrayInt;
typedef std::pair<ArrayInt, ArrayInt> PairArray;
class Wine : private std::string, private PairArray
{
public:
// default constructor
Wine();
// initialize label to l, number of years to y,
// vintage years to yr[], bottles to bot[]
Wine(const char *l, int y, const int yr[], const int bot[]);
// initialize label to l, number of years to y,
// create array objects of length y
Wine(const char *l, int y);
~Wine();
void GetBottles();
void Show();
const std::string &Label() const;
int sum();
};
#endif
Code - classes methods
#include "ch14_2_wine.h"
/// Constructors ///
Wine::Wine() : std::string("")
{
}
Wine::Wine(const char *l, int y) : std::string(l), PairArray(ArrayInt(y),ArrayInt(y))
{
}
Wine::Wine(const char *l, int y, const int yr[], const int bot[]) : std::string(l), PairArray(ArrayInt(y),ArrayInt(y))
{
for (int i{}; i < y; i++)
{
PairArray::first[i] = yr[i];
PairArray::second[i] = bot[i];
}
}
/// Destructors ///
Wine::~Wine()
{
}
/// Methods ///
void Wine::GetBottles()
{
std::cout << "Enter " << std::string(*this) << " data for "
<< PairArray::first.size() << " year(s): " << std::endl;
for (int i = 0; i < PairArray::first.size(); ++i)
{
std::cout << "Enter year: ";
std::cin >> PairArray::first[i];
std::cout << "Enter bootles for that year: ";
std::cin >> PairArray::second[i];
}
}
const std::string &Wine::Label() const
{
return (const std::string &)(*this);
}
void Wine::Show()
{
std::cout << "Wine: " << std::string(*this) << std::endl;
std::cout << "Year Bottles" << std::endl;
for (int i = 0; i < PairArray::first.size(); ++i)
{
std::cout << PairArray::first[i] << " ";
std::cout << PairArray::second[i] << std::endl;
}
}
int Wine::sum()
{
int _sum{};
for (int i = 0; i < PairArray::first.size(); ++i)
{
_sum += PairArray::second[i];
}
return _sum;
}
Code - program
// pe14-1.cpp -- using Wine class with containment
#include <iostream>
#include "ch14_2_wine.h"
int main(void)
{
using std::cin;
using std::cout;
using std::endl;
cout << "Enter name of wine: ";
char lab[50];
cin.getline(lab, 50);
cout << "Enter number of years: ";
int yrs;
cin >> yrs;
Wine holding(lab, yrs); // store label, years, give arrays yrs elements
holding.GetBottles(); // solicit input for year, bottle count
holding.Show(); // display object contents
const int YRS = 3;
int y[YRS] = {1993, 1995, 1998};
int b[YRS] = {48, 60, 72};
// create new object, initialize using data in arrays y and b
Wine more("Gushing Grape Red", YRS, y, b);
more.Show();
cout << "Total bottles for " << more.Label() // use Label() method
<< ": " << more.sum() << endl; // use sum() method
cout << "Bye\n";
return 0;
}
/*
And here’s some sample of expected output:
Enter name of wine: Gully Wash
Enter number of years: 4
Enter Gully Wash data for 4 year(s):
Enter year: 1988
Enter bottles for that year: 42
Enter year: 1994
Enter bottles for that year: 58
Enter year: 1998
Enter bottles for that year: 122
Enter year: 2001
Enter bottles for that year: 144
Wine: Gully Wash
Year Bottles
1988 42
1994 58
1998 122
2001 144
Wine: Gushing Grape Red
Year Bottles
1993 48
1995 60
1998 72
Total bottles for Gushing Grape Red: 180
Bye
*/
3 -
Define a QueueTp template. Test it by creating a queue of pointers-to-Worker (as
defined in Listing 14.10
Code - classes prototypes of listing 14.10
#ifndef WORKERMI_H_
#define WORKERMI_H_
#include <string>
class Worker // an abstract base class
{
private:
std::string fullname;
long id;
protected:
virtual void Data() const;
virtual void Get();
public:
Worker() : fullname("no one"), id(0L) {}
Worker(const std::string &s, long n)
: fullname(s), id(n) {}
virtual ~Worker() = 0; // pure virtual function
virtual void Set() = 0;
virtual void Show() const = 0;
};
class Waiter : virtual public Worker
{
private:
int panache;
protected:
void Data() const;
void Get();
public:
Waiter() : Worker(), panache(0) {}
Waiter(const std::string &s, long n, int p = 0)
: Worker(s, n), panache(p) {}
Waiter(const Worker &wk, int p = 0)
: Worker(wk), panache(p) {}
void Set();
void Show() const;
};
class Singer : virtual public Worker
{
protected:
enum
{
other,
alto,
contralto,
soprano,
bass,
baritone,
tenor
};
enum
{
Vtypes = 7
};
void Data() const;
void Get();
private:
static const char *pv[Vtypes]; // string equivs of voice types
int voice;
public:
Singer() : Worker(), voice(other) {}
Singer(const std::string &s, long n, int v = other)
: Worker(s, n), voice(v) {}
Singer(const Worker &wk, int v = other)
: Worker(wk), voice(v) {}
void Set();
void Show() const;
};
// multiple inheritance
class SingingWaiter : public Singer, public Waiter
{
protected:
void Data() const;
void Get();
public:
SingingWaiter() {}
SingingWaiter(const std::string &s, long n, int p = 0,
int v = other)
: Worker(s, n), Waiter(s, n, p), Singer(s, n, v) {}
SingingWaiter(const Worker &wk, int p = 0, int v = other)
: Worker(wk), Waiter(wk, p), Singer(wk, v) {}
SingingWaiter(const Waiter &wt, int v = other)
: Worker(wt), Waiter(wt), Singer(wt, v) {}
SingingWaiter(const Singer &wt, int p = 0)
: Worker(wt), Waiter(wt, p), Singer(wt) {}
void Set();
void Show() const;
};
#endif
Code - classes methods of listing 14.10
#include "ch14_3_listing.h"
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
// Worker methods
Worker::~Worker() {}
// protected methods
void Worker::Data() const
{
cout << "Name: " << fullname << endl;
cout << "Employee ID: " << id << endl;
}
void Worker::Get()
{
getline(cin, fullname);
cout << "Enter worker's ID: ";
cin >> id;
while (cin.get() != '\n')
continue;
}
// Waiter methods
void Waiter::Set()
{
cout << "Enter waiter's name: ";
Worker::Get();
Get();
}
void Waiter::Show() const
{
cout << "Category: waiter\n";
Worker::Data();
Data();
}
// protected methods
void Waiter::Data() const
{
cout << "Panache rating: " << panache << endl;
}
void Waiter::Get()
{
cout << "Enter waiter's panache rating: ";
cin >> panache;
while (cin.get() != '\n')
continue;
}
// Singer methods
// char *Singer::pv[Singer::Vtypes] = {"other", "alto", "contralto","soprano", "bass", "baritone", "tenor"};
const char* Singer::pv[Singer::Vtypes] = {"other", "alto", "contralto","soprano", "bass", "baritone", "tenor"};
void Singer::Set()
{
cout << "Enter singer's name: ";
Worker::Get();
Get();
}
void Singer::Show() const
{
cout << "Category: singer\n";
Worker::Data();
Data();
}
// protected methods
void Singer::Data() const
{
cout << "Vocal range: " << pv[voice] << endl;
}
void Singer::Get()
{
cout << "Enter number for singer's vocal range:\n";
int i;
for (i = 0; i < Vtypes; i++)
{
cout << i << ": " << pv[i] << " ";
if (i % 4 == 3)
cout << endl;
}
if (i % 4 != 0)
cout << '\n';
cin >> voice;
while (cin.get() != '\n')
continue;
}
// SingingWaiter methods
void SingingWaiter::Data() const
{
Singer::Data();
Waiter::Data();
}
void SingingWaiter::Get()
{
Waiter::Get();
Singer::Get();
}
void SingingWaiter::Set()
{
cout << "Enter singing waiter's name: ";
Worker::Get();
Get();
}
void SingingWaiter::Show() const
{
cout << "Category: singing waiter\n";
Worker::Data();
Data();
}
Methods like below will only work in the same place as prototypes
For template methods in files outside of a header, you need to use template <> with specified data recovered via T;
Code - classes prototypes and methods
#ifndef QUEUE_TP_H_
#define QUEUE_TP_H_
#include <string>
#include <iostream>
#include <typeinfo> // check for class type pointers https://en.cppreference.com/w/cpp/types/is_pointer
#include "ch14_3_listing.h"
// based on exercise 12_5 queue
template <typename T>
class QueueTp
{
private:
// Node is a nested structure definition local to this class
struct Node
{
T item;
struct Node *next;
};
// static int Q_SIZE {10}; // modifiable static value - will workj the same in this case
enum // constant value that won't change throughout the program,
{
Q_SIZE = 10
};
// private class members
Node *front; // pointer to front of Queue
Node *rear; // pointer to rear of Queue
int items; // current number of items in Queue
const int qsize; // maximum number of items in Queue
// Preemptive definitions to prevent public copying
// (you can also make deep copy definitions instead)
QueueTp(const QueueTp &q) : qsize(0) {}
QueueTp &operator=(const QueueTp &q) { return *this; }
public:
QueueTp(int qs = Q_SIZE); // default constructor for QueueTp queue with a qs limit
QueueTp(T); // create queue with a T value
~QueueTp();
bool isempty() const;
bool isfull() const;
int queuecount() const;
void show() const;
bool enqueue(const T &item); // add item to end
bool dequeue(T &item); // remove item from front
};
#endif
/// Constructors ///
template <typename T>
QueueTp<T>::QueueTp(int qs) : qsize(qs)
{
front = rear = NULL; // or nullptr
items = 0;
}
template <typename T>
QueueTp<T>::QueueTp(T)
{
Node *temp;
while (front != NULL) // while queue is not yet empty
{
temp = front; // save address of front item
enqueue(temp->item); // add item to the end
front = front->next; // reset pointer to next item
delete temp; // delete former front
}
}
template <typename T>
QueueTp<T>::~QueueTp()
{
Node *temp;
while (front != NULL) // while queue is not yet empty
{
temp = front; // save address of front item
front = front->next; // reset pointer to next item
delete temp; // delete former front
}
}
/// Methods ///
template <typename T>
bool QueueTp<T>::isempty() const
{
return items == 0;
}
template <typename T>
bool QueueTp<T>::isfull() const
{
return items == qsize;
}
template <typename T>
int QueueTp<T>::queuecount() const
{
return items;
}
// Add item to queue
template <typename T>
bool QueueTp<T>::enqueue(const T &item)
{
if (isfull())
return false;
Node *add = new Node; // create node
// on failure, new throws std::bad_alloc exception
add->item = item; // set node pointers
add->next = NULL; // or nullptr;
items++;
if (front == NULL) // if queue is empty,
front = add; // place item at front
else
rear->next = add; // else place at rear
rear = add; // have rear point to new node
return true;
}
// Place front item into item variable and remove from queue
template <typename T>
bool QueueTp<T>::dequeue(T &item)
{
if (front == NULL)
return false;
item = front->item; // set item to first item in queue
items--;
Node *temp = front; // save location of first item
front = front->next; // reset front to next item
delete temp; // delete former first item
if (items == 0)
rear = NULL;
return true;
}
template <typename T>
void QueueTp<T>::show() const
{
std::cout << "Number of all items in QueueTp: " << items - 1 << "\n";
std::cout << "Current item on the end of QueueTp\n";
// due to MI, derived classes will be detected as ABC class
if (typeid(front->item) == typeid(Worker *))
{
front->item->Show();
}
else if (std::is_pointer_v<T>)
{
std::cout << "\n\tPointer to unknown class";
}
else
{
std::cout << "\n\tPointer to unknown data";
}
}
Code - program
// workmi.cpp -- multiple inheritance
// compile with workermi.cpp
#include <iostream>
#include <cstring>
// #include "ch14_3_listing.h"
#include "ch14_3_wk.h"
const int SIZE = 5;
int main()
{
using std::cin;
using std::cout;
using std::endl;
using std::strchr;
Worker *lolas; // Worker *lolas[SIZE];
QueueTp<Worker *> lolasQueue; //
int ct;
for (ct = 0; ct < SIZE; ct++)
{
char choice;
cout << "Enter the employee category:\n"
<< "w: waiter s: singer "
<< "t: singing waiter q: quit\n";
cin >> choice;
while (strchr("wstq", choice) == NULL)
{
cout << "Please enter a w, s, t, or q: ";
cin >> choice;
}
if (choice == 'q')
break;
switch (choice)
{
case 'w':
lolas = new Waiter; // lolas[ct] = new Waiter;
break;
case 's':
lolas = new Singer; // lolas[ct] = new Singer;
break;
case 't':
lolas = new SingingWaiter; // lolas[ct] = new SingingWaiter;
break;
}
cin.get();
lolas->Set(); // lolas[ct]->Set();
lolasQueue.enqueue(lolas);
}
cout << "\nHere is your staff:\n";
int i;
for (i = 0; i < ct; i++)
{
cout << endl;
lolasQueue.show(); // lolas->Show();
lolasQueue.dequeue(lolas); // it will automatically handle delete
// delete lolas;
}
delete lolas; //
// for (i = 0; i < ct; i++)
// delete lolas[i];
cout << "Bye.\n";
return 0;
}
/*
Here is a sample run of the program in Listings 14.10, 14.11, and 14.12:
Enter the employee category:
w: waiter s: singer t: singing waiter q: quit
w
Enter waiter's name: Wally Slipshod
Enter worker's ID: 1040
Enter waiter's panache rating: 4
Enter the employee category:
w: waiter s: singer t: singing waiter q: quit
s
Enter singer's name: Sinclair Parma
Enter worker's ID: 1044
Enter number for singer's vocal range:
0: other 1: alto 2: contralto 3: soprano
4: bass 5: baritone 6: tenor
5
Enter the employee category:
w: waiter s: singer t: singing waiter q: quit
t
Enter singing waiter's name: Natasha Gargalova
Enter worker's ID: 1021
Enter waiter's panache rating: 6
Enter number for singer's vocal range:
0: other 1: alto 2: contralto 3: soprano
4: bass 5: baritone 6: tenor
3
Enter the employee category:
w: waiter s: singer t: singing waiter q: quit
q
Here is your staff:
Category: waiter
Name: Wally Slipshod
Employee ID: 1040
Panache rating: 4
Category: singer
Name: Sinclair Parma
Employee ID: 1044
Vocal range: baritone
Category: singing waiter
Name: Natasha Gargalova
Employee ID: 1021
Vocal range: soprano
Panache rating: 6
Bye.
*/
Compile using:
4 -
A Person class holds the first name and the last name of a person. In addition to its
constructors, it has a Show() method that displays both names. A Gunslinger class
derives virtually from the Person class. It has a Draw() member that returns a type
double value representing a gunslinger’s draw time. The class also has an int member
representing the number of notches on a gunslinger’s gun. Finally, it has a
Show() function that displays all this information.
A PokerPlayer class derives virtually from the Person class. It has a Draw() member
that returns a random number in the range 1 through 52, representing a card
value. (Optionally, you could define a Card class with suit and face value members
and use a Card return value for Draw().) The PokerPlayer class uses the Person
show() function.The BadDude class derives publicly from the Gunslinger and
PokerPlayer classes. It has a Gdraw() member that returns a bad dude’s draw time
and a Cdraw() member that returns the next card drawn. It has an appropriate
Show() function. Define all these classes and methods, along with any other necessary
methods (such as methods for setting object values) and test them in a simple
program similar to that in Listing 14.12.
Code - classes prototypes
#ifndef _PPL_H_
#define _PPL_H_
#include <iostream>
#include <string>
#include <random> // for Gunslinger::Draw
// ---------------------------------
class Person
{
private:
std::string sFirstName;
std::string sLastName;
public:
Person(std::string fn = "", std::string ln = ""); // Inefficient constructor but simple
// Person::Person(std::string&& fn = "", std::string&& ln = ""); // Efficient constructor (pass by ref)
~Person();
virtual void Show() const;
virtual void Set();
};
// ---------------------------------
class Gunslinger : virtual public Person
{
private:
int iNotches;
public:
Gunslinger(int notc = 6, std::string fn = "", std::string ln = "");
~Gunslinger(){};
double Draw();
virtual void Show() const;
virtual void Set();
};
// ---------------------------------
class PokerPlayer : virtual public Person
{
public:
PokerPlayer(std::string fn = "", std::string ln = "") : Person(fn, ln){};
~PokerPlayer();
int Draw();
virtual void Show() { Person::Show(); std::cout << "Type: Poker player"; }; // PokerPlayer has to use Person::Show according to task;
virtual void Set(){ Person::Set(); };
};
// ---------------------------------
class BadDude : public Gunslinger, public PokerPlayer
{
private:
int iNextCard = 1;
double dDrawTime = (double)(rand() % 1000) / 1000; // Gunslinger is purely random, while BadDude have constant Draw Time
public:
BadDude(int notc = 6, std::string fn = "", std::string ln = "") : Person(), Gunslinger(), PokerPlayer(){};
~BadDude();
double Gdraw(){ return dDrawTime; };
int Cdraw(){return iNextCard > 51 ? iNextCard = 0 : ++iNextCard;};
virtual void Set();
};
#endif
Code - classes methods
#include "ch14_4_ppl.h"
/// Person /// ---------------------------------
//// Inefficient constructor - leverage copy constructor
Person::Person(std::string fn, std::string ln)
{
sFirstName = fn;
sLastName = ln;
}
//// Efficient constructor -
// |lvalue - left operand modifiable value eg.: int asd, char asd |
// |rvalue - Pulls or fetches the value stored in a variable or constant to the right side |
// |int num = 39 | // to lvalue num, rvalue 39 is assigned
// | std::string&& - is known as an rvalue reference, which allows a function to accept arguments that are temporary objects or literal values.
// | std::string& - is a regular reference. It can only bind to existing objects, not literals or temporary objects.
//// bind to temporary objects and rvalues. The std::move function is used to convert the lvalues to rvalues,
//// enabling the move constructor of std::string to be invoked, which can be more efficient than the copy constructor
// Person::Person(std::string&& fn, std::string&& ln) : firstName(std::move(fn)), lastName(std::move(ln))
// {
// }
Person::~Person()
{
}
void Person::Show() const
{
std::cout << std::endl;
std::cout << "First name: " << sFirstName;
std::cout << std::endl;
std::cout << "Last name: " << sLastName;
}
void Person::Set()
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Enter first name: ";
std::getline(std::cin, sFirstName);
std::cout << "Enter last name: ";
std::getline(std::cin, sLastName);
}
/// Gunslinger /// ---------------------------------
Gunslinger::Gunslinger(int notc, std::string fn, std::string ln)
: Person(fn, ln)
{
iNotches = notc;
}
// Gunslinger::Gunslinger(int notc, std::string fn, std::string ln) : Person(std::move(fn), std::move(ln)){}
// return time of draw from 0 to 1 second
double Gunslinger::Draw()
{
// // Simpler my solution
return (double)(rand() % 1000) / 1000;
// // Simple solution
// double dMax = 1;
// double dMin = 0;
// double f = (double)rand() / RAND_MAX;
// return dMin + f * (dMax - dMin);
// //
// std::random_device rd; // Will be used to obtain a seed for the random number engine
// std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
// std::uniform_real_distribution<> dis(0.0, 1.0);
// return dis(gen);
}
void Gunslinger::Show() const
{
Person::Show(); // can be used if Person::Show is also const cast
std::cout << std::endl;
std::cout << "Notches: " << iNotches;
std::cout << "Type: Gunslinger";
}
void Gunslinger::Set()
{
std::cout << "Enter number of notches on a gun: ";
while (!(std::cin >> iNotches || iNotches <= 0))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a positive number: ";
}
Person::Set();
}
/// PokerPlayer /// ---------------------------------
// return card value from 1 to 52
int PokerPlayer::Draw()
{
// simple solution
return rand() % 52 + 1;
// // Advanced solution
// std::random_device rd;
// std::mt19937 gen(rd());
// return std::uniform_int_distribution<>(1, 52)(gen);
}
/// BadDude /// ---------------------------------
void BadDude::Set()
{
std::cout << "Enter draw time to shoot: ";
while (!(std::cin >> dDrawTime || dDrawTime <= 0))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a positive number: ";
}
Person::Set();
}
Code - program
#include <iostream>
#include <cstring>
#include "ch14_4_ppl.h"
// Listing 14.12 - changed only name of classes for obj creation and questions
const int SIZE = 5;
int main()
{
using std::cin;
using std::cout;
using std::endl;
using std::strchr;
Person *lolas[SIZE];
int ct;
for (ct = 0; ct < SIZE; ct++)
{
char choice;
cout << "Enter the player category:\n"
<< "g: gunslinger p: poker player "
<< "b: bad dude q: quit\n";
cin >> choice;
while (strchr("gpbq", choice) == NULL)
{
cout << "Please enter a g, p, b, or q: ";
cin >> choice;
}
if (choice == 'q')
break;
switch (choice)
{
case 'g':
lolas[ct] = new Gunslinger;
break;
case 'p':
lolas[ct] = new PokerPlayer;
break;
case 'b':
lolas[ct] = new BadDude;
break;
}
cin.get();
lolas[ct]->Set();
}
cout << "\nHere is your players:\n";
int i;
for (i = 0; i < ct; i++)
{
cout << endl;
lolas[i]->Show();
}
for (i = 0; i < ct; i++)
delete lolas[i];
cout << "Bye.\n";
return 0;
}
5 - Here are some class declarations:
// emp.h -- header file for abstr_emp class and children
#include <iostream>
#include <string>
class abstr_emp
{
private:
std::string fname; // abstr_emp's first name
std::string lname; // abstr_emp's last name
std::string job;
public:
abstr_emp();
abstr_emp(const std::string &fn, const std::string &ln,
const std::string &j);
virtual void ShowAll() const; // labels and shows all data
virtual void SetAll(); // prompts user for values
friend std::ostream &
operator<<(std::ostream &os, const abstr_emp &e);
// just displays first and last name
virtual ~abstr_emp() = 0; // virtual base class
};
class employee : public abstr_emp
{
public:
employee();
employee(const std::string &fn, const std::string &ln,
const std::string &j);
virtual void ShowAll() const;
virtual void SetAll();
};
class manager : virtual public abstr_emp
{
private:
int inchargeof; // number of abstr_emps managed
protected:
int InChargeOf() const { return inchargeof; } // output
int &InChargeOf() { return inchargeof; } // input
public:
manager();
manager(const std::string &fn, const std::string &ln,
const std::string &j, int ico = 0);
manager(const abstr_emp &e, int ico);
manager(const manager &m);
virtual void ShowAll() const;
virtual void SetAll();
};
class fink : virtual public abstr_emp
{
private:
std::string reportsto; // to whom fink reports
protected:
const std::string ReportsTo() const { return reportsto; }
std::string &ReportsTo() { return reportsto; }
public:
fink();
fink(const std::string &fn, const std::string &ln,
const std::string &j, const std::string &rpo);
fink(const abstr_emp &e, const std::string &rpo);
fink(const fink &e);
virtual void ShowAll() const;
virtual void SetAll();
};
class highfink : public manager, public fink // management fink
{
public:
highfink();
highfink(const std::string &fn, const std::string &ln,
const std::string &j, const std::string &rpo,
int ico);
highfink(const abstr_emp &e, const std::string &rpo, int ico);
highfink(const fink &f, int ico);
highfink(const manager &m, const std::string &rpo);
highfink(const highfink &h);
virtual void ShowAll() const;
virtual void SetAll();
};
Note that the class hierarchy uses MI with a virtual base class, so keep in mind the
special rules for constructor initialization lists for that case.Also note the presence
of some protected-access methods.This simplifies the code for some of the
highfink methods. (Note, for example, that if highfink::ShowAll() simply
calls fink::ShowAll() and manager::ShowAll(), it winds up calling
abstr_emp::ShowAll() twice). Provide the class method implementations and test
the classes in a program. Here is a minimal test program:
// pe14-5.cpp
// useemp1.cpp -- using the abstr_emp classes
#include <iostream>
using namespace std;
#include "emp.h"
int main(void)
{
employee em("Trip", "Harris", "Thumper");
cout << em << endl;
em.ShowAll();
manager ma("Amorphia", "Spindragon", "Nuancer", 5);
cout << ma << endl;
ma.ShowAll();
fink fi("Matt", "Oggs", "Oiler", "Juno Barr");
cout << fi << endl;
fi.ShowAll();
highfink hf(ma, "Curly Kew"); // recruitment?
hf.ShowAll();
cout << "Press a key for next phase:\n";
cin.get();
highfink hf2;
hf2.SetAll();
cout << "Using an abstr_emp * pointer:\n";
abstr_emp *tri[4] = {&em, &fi, &hf, &hf2};
for (int i = 0; i < 4; i++)
tri[i]->ShowAll();
return 0;
}
1. Why is no assignment operator defined?
2. Why are ShowAll() and SetAll() virtual?
3. Why is abstr_emp a virtual base class?
4. Why does the highfink class have no data section?
5. Why is only one version of operator<<() needed?
6. What would happen if the end of the program were replaced with this code?
1. There is no allocation of data directly in class, thus deep copy is not necessary
2. Method can be overridden in a derived class, enabling runtime polymorphism.
"When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class’s version of the method."
3. Because one of the methods (in this case destructor) is a pure virtual function.
4. All necessary data is stored in objects of a 2 base classes, highfink only extend functional part of inherited classes and don't have new data
5. Because it is publicly inherited, thus can be used in any class that inherits it
6. You cannot declare ABC type of class directly.
Code - classes prototypes
// emp.h -- header file for abstr_emp class and children
#ifndef _EMP_H_
#define _EMP_H_
#include <iostream>
#include <string>
class abstr_emp
{
private:
std::string fname; // abstr_emp's first name
std::string lname; // abstr_emp's last name
std::string job;
public:
abstr_emp();
abstr_emp(const std::string &fn, const std::string &ln, const std::string &j);
virtual void ShowAll() const; // labels and shows all data
virtual void SetAll(); // prompts user for values
friend std::ostream &operator<<(std::ostream &os, const abstr_emp &e);
// just displays first and last name
virtual ~abstr_emp() = 0; // virtual base class
};
class employee : public abstr_emp
{
public:
employee();
employee(const std::string &fn, const std::string &ln, const std::string &j);
virtual void ShowAll() const;
virtual void SetAll();
};
class manager : virtual public abstr_emp
{
private:
int inchargeof; // number of abstr_emps managed
protected:
int InChargeOf() const { return inchargeof; } // output
int &InChargeOf() { return inchargeof; } // input
public:
manager();
manager(const std::string &fn, const std::string &ln,
const std::string &j, int ico = 0);
manager(const abstr_emp &e, int ico);
manager(const manager &m);
virtual void ShowAll() const;
virtual void SetAll();
};
class fink : virtual public abstr_emp
{
private:
std::string reportsto; // to whom fink reports
protected:
const std::string ReportsTo() const { return reportsto; }
std::string &ReportsTo() { return reportsto; }
public:
fink();
fink(const std::string &fn, const std::string &ln,
const std::string &j, const std::string &rpo);
fink(const abstr_emp &e, const std::string &rpo);
fink(const fink &e);
virtual void ShowAll() const;
virtual void SetAll();
};
class highfink : public manager, public fink // management fink
{
public:
highfink();
highfink(const std::string &fn, const std::string &ln,
const std::string &j, const std::string &rpo,
int ico);
highfink(const abstr_emp &e, const std::string &rpo, int ico);
highfink(const fink &f, int ico);
highfink(const manager &m, const std::string &rpo);
highfink(const highfink &h);
virtual void ShowAll() const;
virtual void SetAll();
};
#endif
Code - classes methods
#include "ch14_5_emp.h"
/// abstr_emp /// --------------------------------------
abstr_emp::abstr_emp()
{
fname = "-";
lname = "-";
job = "-";
}
abstr_emp::abstr_emp(const std::string &fn, const std::string &ln, const std::string &j)
{
fname = fn;
lname = ln;
job = j;
}
void abstr_emp::ShowAll() const
{
std::cout << std::endl;
std::cout << "First name: " << fname;
std::cout << std::endl;
std::cout << "Last name: " << lname;
std::cout << std::endl;
std::cout << "Profession: " << job;
std::cout << std::endl;
}
void abstr_emp::SetAll()
{
std::cout << std::endl;
std::cout << "Enter the first name: ";
std::getline(std::cin, fname);
std::cout << "Enter the last name: ";
std::getline(std::cin, lname);
std::cout << "Enter the profession: ";
std::getline(std::cin, job);
}
std::ostream &operator<<(std::ostream &os, const abstr_emp &e)
{
os << e.fname << " " << e.lname << ", " << e.job;
return os;
}
abstr_emp::~abstr_emp()
{
std::cout << std::endl;
std::cout << "\tEliminated: " << fname << " " << lname;
}
/// employee /// --------------------------------------
employee::employee() : abstr_emp()
{
}
employee::employee(const std::string &fn, const std::string &ln, const std::string &j) : abstr_emp(fn, ln, j)
{
}
void employee::ShowAll() const
{
abstr_emp::ShowAll();
}
void employee::SetAll()
{
abstr_emp::SetAll();
}
/// manager /// --------------------------------------
manager::manager() : abstr_emp()
{
inchargeof = 0;
}
manager::manager(const std::string &fn, const std::string &ln,
const std::string &j, int ico) : abstr_emp(fn, ln, j)
{
inchargeof = ico;
}
// Base class constructor is automatically invoked unless another
// constructor is explicitly called in the derived class for abstr_emp(e) - so called shallow copy
manager::manager(const abstr_emp &e, int ico) : abstr_emp(e)
{
inchargeof = ico;
}
manager::manager(const manager &m) : abstr_emp(m)
{
inchargeof = m.InChargeOf();
}
void manager::ShowAll() const
{
abstr_emp::ShowAll();
std::cout << std::endl;
std::cout << "Manager is in charge of: " << inchargeof << " people";
std::cout << std::endl;
}
void manager::SetAll()
{
abstr_emp::SetAll();
std::cout << "Enter the amount of people manager will be in charge of: ";
while (!(std::cin >> inchargeof || inchargeof <= 0))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a positive number: ";
}
std::cin.clear(); // reset input after putting in data
while (std::cin.get() != '\n')
continue; // get rid of bad input
}
/// fink /// --------------------------------------
fink::fink() : abstr_emp()
{
reportsto = "-";
}
fink::fink(const std::string &fn, const std::string &ln,
const std::string &j, const std::string &rpo) : abstr_emp(fn, ln, j)
{
reportsto = rpo;
}
fink::fink(const abstr_emp &e, const std::string &rpo) : abstr_emp(e)
{
reportsto = rpo;
}
fink::fink(const fink &e) : abstr_emp(e)
{
reportsto = e.reportsto;
// reportsto = e.ReportsTo();
// reportsto = this->ReportsTo(); // ??
}
void fink::ShowAll() const
{
abstr_emp::ShowAll();
std::cout << "Fink reports to: " << reportsto;
std::cout << std::endl;
}
void fink::SetAll()
{
abstr_emp::SetAll();
std::cout << "Enter superior to reports to: ";
std::getline(std::cin, reportsto);
}
/// high fink /// --------------------------------------
highfink::highfink() : abstr_emp(), manager(), fink()
{
}
highfink::highfink(const std::string &fn, const std::string &ln,
const std::string &j, const std::string &rpo,
int ico) : abstr_emp(fn, ln, j), manager(fn, ln, j, ico), fink(fn, ln, j, rpo)
{
}
highfink::highfink(const abstr_emp &e, const std::string &rpo, int ico) : abstr_emp(e), manager(e, ico), fink(e, rpo)
{
}
highfink::highfink(const fink &f, int ico) : abstr_emp(f), manager(f, ico), fink(f)
{
}
highfink::highfink(const manager &m, const std::string &rpo) : abstr_emp(m), manager(m), fink(m, rpo)
{
}
highfink::highfink(const highfink &h) : abstr_emp(h), manager(h), fink(h)
{
}
void highfink::ShowAll() const
{
manager::ShowAll();
std::cout << std::endl;
std::cout << "High fink reports to: " << fink::ReportsTo();
std::cout << std::endl;
}
void highfink::SetAll()
{
manager::SetAll();
fink::SetAll(); // need protected setReportsto to be shorter
}
Code - program
// pe14-5.cpp
#include <iostream>
#include "ch14_5_emp.h"
using namespace std;
int main(void)
{
employee em("Trip", "Harris", "Thumper");
cout << em << endl;
em.ShowAll();
manager ma("Amorphia", "Spindragon", "Nuancer", 5);
cout << ma << endl;
ma.ShowAll();
fink fi("Matt", "Oggs", "Oiler", "Juno Barr");
cout << fi << endl;
fi.ShowAll();
highfink hf(ma, "Curly Kew"); // recruitment?
hf.ShowAll();
cout << "Press a key for next phase:\n";
cin.get();
highfink hf2;
hf2.SetAll();
// cout << "Using an abstr_emp * pointer:\n";
// abstr_emp *tri[4] = {&em, &fi, &hf, &hf2};
// for (int i = 0; i < 4; i++)
// tri[i]->ShowAll();
// Question tests
/* array of abstract class "abstr_emp" is not allowed:C/C++(604)
ch14_5.cpp(35, 15): function "abstr_emp::~abstr_emp" is a pure virtual function */
// abstr_emp tri[4] = {em, fi, hf, hf2};
// for (int i = 0; i < 4; i++)
// tri[i].ShowAll();
return 0;
}
Chapter 15
1 -
Modify the Tv and Remote classes as follows:
a. Make them mutual friends.
b. Add a state variable member to the Remote class that describes whether the
remote control is in normal or interactive mode.
c. Add a Remote method that displays the mode.
d. Provide the Tv class with a method for toggling the new Remote member.
This method should work only if the TV is in the on state.
Write a short program that tests these new features.
Code - classes prototypes
// tv.h -- Tv and Remote classes
#ifndef TV_H_
#define TV_H_
class Remote; // a. Make them mutual friends. -----------------
class Tv
{
public:
friend class Remote; // Remote can access Tv private parts
enum
{
Off,
On
};
enum
{
MinVal,
MaxVal = 20
};
enum
{
Antenna,
Cable
};
enum
{
TV,
DVD
};
Tv(int s = Off, int mc = 125) : state(s), volume(5),
maxchannel(mc), channel(2), mode(Cable), input(TV) {}
void onoff() { state = (state == On) ? Off : On; }
bool ison() const { return state == On; }
bool volup();
bool voldown();
void chanup();
void chandown();
void set_mode() { mode = (mode == Antenna) ? Cable : Antenna; }
void set_input() { input = (input == TV) ? DVD : TV; }
void settings() const; // display all settings
void all_settings(Remote &r) const; // display all settings, including remote // b.
// d. Provide the Tv class with a method for toggling the new Remote member.
// This method should work only if the TV is in the on state.
void change_mode(Remote &r);
private:
int state; // on or off
int volume; // assumed to be digitized
int maxchannel; // maximum number of channels
int channel; // current channel setting
int mode; // broadcast or cable
int input; // TV or DVD
};
class Remote
{
friend class Tv; // a. Make them mutual friends. -----------------
private:
int mode; // controls TV or DVD
bool state_mode;
enum
{
NORMAL_MODE,
INTERACTIVE_MODE
};
public:
Remote(int m = Tv::TV, bool s = NORMAL_MODE) : mode(m), state_mode(s) {}
bool volup(Tv &t) { return t.volup(); }
bool voldown(Tv &t) { return t.voldown(); }
void onoff(Tv &t) { t.onoff(); }
void chanup(Tv &t) { t.chanup(); }
void chandown(Tv &t) { t.chandown(); }
void set_chan(Tv &t, int c) { t.channel = c; }
void set_mode(Tv &t) { t.set_mode(); }
void set_input(Tv &t) { t.set_input(); }
// b. Add a state variable member to the Remote class that describes whether the
// remote control is in normal or interactive mode
// void change_mode() { state_mode = (state_mode == NORMAL_MODE) ? INTERACTIVE_MODE : NORMAL_MODE; }
void change_mode() { state_mode ^= 1; } // the same but XOR
// c. Add a Remote method that displays the mode.
void display_mode()
{
std::cout << "\n"
<< (state_mode == NORMAL_MODE ? "Normal mode" : "Interactive mode");
}
};
#endif
Code - classes methods
// tv.cpp -- methods for the Tv class (Remote methods are inline)
#include <iostream>
#include "ch15_1_tv.h"
bool Tv::volup()
{
if (volume < MaxVal)
{
volume++;
return true;
}
else
return false;
}
bool Tv::voldown()
{
if (volume > MinVal)
{
volume--;
return true;
}
else
return false;
}
void Tv::chanup()
{
if (channel < maxchannel)
channel++;
else
channel = 1;
}
void Tv::chandown()
{
if (channel > 1)
channel--;
else
channel = maxchannel;
}
void Tv::settings() const
{
using std::cout;
using std::endl;
cout << "TV is " << (state == Off ? "Off" : "On") << endl;
if (state == On)
{
cout << "Volume setting = " << volume << endl;
cout << "Channel setting = " << channel << endl;
cout << "Mode = "
<< (mode == Antenna ? "antenna" : "cable") << endl;
cout << "Input = "
<< (input == TV ? "TV" : "DVD") << endl;
}
}
// b.
void Tv::all_settings(Remote &r) const
{
using std::cout;
using std::endl;
cout << "TV is " << (state == Off ? "Off" : "On") << endl;
if (state == On)
{
cout << "Volume setting = " << volume << endl;
cout << "Channel setting = " << channel << endl;
cout << "Mode = "
<< (mode == Antenna ? "antenna" : "cable") << endl;
cout << "Interactive mode = "
<< (r.state_mode == r.INTERACTIVE_MODE ? "No" : "Yes") << endl;
cout << "Input = "
<< (input == TV ? "TV" : "DVD") << endl;
}
}
void Tv::change_mode(Remote &r)
{
r.change_mode();
}
Code - program
// use_tv.cpp -- using the Tv and Remote classes
#include <iostream>
#include "ch15_1_tv.h"
int main()
{
using std::cout;
Tv s42;
cout << "Initial settings for 42\" TV:\n";
s42.settings();
s42.onoff();
s42.chanup();
cout << "\nAdjusted settings for 42\" TV:\n";
s42.settings();
Remote grey;
grey.set_chan(s42, 10);
grey.volup(s42);
grey.volup(s42);
// - display changes
cout << "\n42\" Change display mode:\n";
grey.display_mode();
grey.change_mode();
grey.display_mode();
cout << "\n42\" settings after using remote:\n";
s42.settings();
Tv s58(Tv::On);
s58.set_mode();
grey.set_chan(s58, 28);
cout << "\n58\" settings:\n";
s58.settings();
// - display changes
cout << "\n42\" Change display mode via Tv:\n";
s58.all_settings(grey);
s58.change_mode(grey);
cout << "\n";
s58.all_settings(grey);
return 0;
}
2 -
Modify Listing 15.11 (error4.cpp) so that the two exception types are classes derived from the
logic_error class provided by the header file. Have each what()
method report the function name and the nature of the problem.The exception
objects need not hold the bad values; they should just support the what() method.
Code - program
#include <iostream>
#include <cmath> // or math.h, unix users may need -lm flag
#include <stdexcept>
// function prototypes
double hmean(double a, double b);
double gmean(double a, double b);
int main()
{
using std::cin;
using std::cout;
using std::endl;
double x, y, z;
cout << "Enter two numbers: ";
while (cin >> x >> y)
{
try
{ // start of try block
z = hmean(x, y);
cout << "Harmonic mean of " << x << " and " << y
<< " is " << z << endl;
cout << "Geometric mean of " << x << " and " << y
<< " is " << gmean(x, y) << endl;
cout << "Enter next set of numbers <q to quit>: ";
} // end of try block
catch (const std::invalid_argument &ia) // start of catch block
{
std::cout << "Caught: " << ia.what() << std::endl;
std::cout << "Type: " << typeid(ia).name() << std::endl;
continue;
}
catch (const std::exception &e) // other errors
{
std::cout << "Caught: " << e.what();
std::cout << "Type: " << typeid(e).name();
break;
}
}
cout << "\nBye!\n";
return 0;
}
double hmean(double a, double b)
{
if (a == -b)
throw std::invalid_argument("hmean() invalid arguments: a == -b\n");
return 2.0 * a * b / (a + b);
}
double gmean(double a, double b)
{
if (a < 0 || b < 0)
throw std::runtime_error("gmean() arguments should be >= 0\n");
return std::sqrt(a * b);
}
/*
// Listing 15.10
// exc_mean.h -- exception classes for hmean(), gmean()
#include <iostream>
class bad_hmean
{
private:
double v1;
double v2;
public:
bad_hmean(double a = 0, double b = 0) : v1(a), v2(b) {}
void mesg();
};
inline void bad_hmean::mesg()
{
std::cout << "hmean(" << v1 << ", " << v2 << "): "
<< "invalid arguments: a = -b\n";
}
class bad_gmean
{
public:
double v1;
double v2;
bad_gmean(double a = 0, double b = 0) : v1(a), v2(b) {}
const char *mesg();
};
inline const char *bad_gmean::mesg()
{
return "gmean() arguments should be >= 0\n";
}
// (Listing 15.11) error4.cpp – using exception classes
#include <iostream>
#include <cmath> // or math.h, unix users may need -lm flag
#include "exc_mean.h"
// function prototypes
double hmean(double a, double b);
double gmean(double a, double b);
int main()
{
using std::cin;
using std::cout;
using std::endl;
double x, y, z;
cout << "Enter two numbers: ";
while (cin >> x >> y)
{
try
{ // start of try block
z = hmean(x, y);
cout << "Harmonic mean of " << x << " and " << y
<< " is " << z << endl;
cout << "Geometric mean of " << x << " and " << y
<< " is " << gmean(x, y) << endl;
cout << "Enter next set of numbers <q to quit>: ";
} // end of try block
catch (bad_hmean &bg) // start of catch block
{
bg.mesg();
cout << "Try again.\n";
continue;
}
catch (bad_gmean &hg)
{
cout << hg.mesg();
cout << "Values used: " << hg.v1 << ", "
<< hg.v2 << endl;
cout << "Sorry, you don't get to play any more.\n";
break;
} // end of catch block
}
cout << "Bye!\n";
return 0;
}
double hmean(double a, double b)
{
if (a == -b)
throw bad_hmean(a, b);
return 2.0 * a * b / (a + b);
}
double gmean(double a, double b)
{
if (a < 0 || b < 0)
throw bad_gmean(a, b);
return std::sqrt(a * b);
}
*/
/*
Here’s a sample run of the program, one that gets terminated by bad input for the
gmean() function:
Enter two numbers: 4 12
Harmonic mean of 4 and 12 is 6
Geometric mean of 4 and 12 is 6.9282
Enter next set of numbers <q to quit>: 5 -5
hmean(5, -5): invalid arguments: a = -b
Try again.
5 -2
Harmonic mean of 5 and -2 is -6.66667
gmean() arguments should be >= 0
Values used: 5, -2
Sorry, you don't get to play any more.
Bye!
One
*/
3 -
This exercise is the same as Programming Exercise 2, except that the exceptions
should be derived from a base class (itself derived from logic_error) that stores the
two argument values, the exceptions should have a method that reports these values
as well as the function name, and a single catch block that catches the base-class
exemption should be used for both exceptions, with either exception causing the
loop to terminate.
Code - program
#include <iostream>
#include <cmath> // or math.h, unix users may need -lm flag
#include <stdexcept>
// function prototypes
double hmean(double a, double b);
double gmean(double a, double b);
int main()
{
using std::cin;
using std::cout;
using std::endl;
double x, y, z;
cout << "Enter two numbers: ";
while (cin >> x >> y)
{
try
{ // start of try block
z = hmean(x, y);
cout << "Harmonic mean of " << x << " and " << y
<< " is " << z << endl;
cout << "Geometric mean of " << x << " and " << y
<< " is " << gmean(x, y) << endl;
cout << "Enter next set of numbers <q to quit>: ";
} // end of try block
catch (const std::exception &e) // other errors
{
std::cout << "Caught: " << e.what();
std::cout << "Type: " << typeid(e).name();
break;
}
}
cout << "\nBye!\n";
return 0;
}
double hmean(double a, double b)
{
if (a == -b)
throw std::logic_error("hmean() invalid arguments: a == -b\n");
return 2.0 * a * b / (a + b);
}
double gmean(double a, double b)
{
if (a < 0 || b < 0)
throw std::logic_error("gmean() arguments should be >= 0\n");
return std::sqrt(a * b);
}
4 -
Listing 15.16 (use_sales.cpp) uses two catch blocks after each try block so that the nbad_index
exception leads to the label_val() method being invoked. Modify the program so
that it uses a single catch block after each try block and uses RTTI to handle
invoking label_val() only when appropriate.
Code - classes prototypes
// sales.h -- exceptions and inheritance
#include <stdexcept>
#include <string>
class Sales
{
public:
enum
{
MONTHS = 12
}; // could be a static const
class bad_index : public std::logic_error
{
private:
int bi; // bad index value
public:
explicit bad_index(int ix,
const std::string &s = "Index error in Sales object\n");
int bi_val() const { return bi; }
virtual ~bad_index() throw() {}
};
explicit Sales(int yy = 0);
Sales(int yy, const double *gr, int n);
virtual ~Sales() {}
int Year() const { return year; }
virtual double operator[](int i) const;
virtual double &operator[](int i);
private:
double gross[MONTHS];
int year;
};
class LabeledSales : public Sales
{
public:
class nbad_index : public Sales::bad_index
{
private:
std::string lbl;
public:
nbad_index(const std::string &lb, int ix,
const std::string &s = "Index error in LabeledSales object\n");
const std::string &label_val() const { return lbl; }
virtual ~nbad_index() throw() {}
};
explicit LabeledSales(const std::string &lb = "none", int yy = 0);
LabeledSales(const std::string &lb, int yy, const double *gr, int n);
virtual ~LabeledSales() {}
const std::string &Label() const { return label; }
virtual double operator[](int i) const;
virtual double &operator[](int i);
private:
std::string label;
};
Code - classes methods
// sales.cpp -- Sales implementation
#include "ch15_4_sales.h"
using std::string;
Sales::bad_index::bad_index(int ix, const string &s)
: std::logic_error(s), bi(ix)
{
}
Sales::Sales(int yy)
{
year = yy;
for (int i = 0; i < MONTHS; ++i)
gross[i] = 0;
}
Sales::Sales(int yy, const double *gr, int n)
{
year = yy;
int lim = (n < MONTHS) ? n : MONTHS;
int i;
for (i = 0; i < lim; ++i)
gross[i] = gr[i];
// for i > n and i < MONTHS
for (; i < MONTHS; ++i)
gross[i] = 0;
}
double Sales::operator[](int i) const
{
if (i < 0 || i >= MONTHS)
throw bad_index(i);
return gross[i];
}
double &Sales::operator[](int i)
{
if (i < 0 || i >= MONTHS)
throw bad_index(i);
return gross[i];
}
LabeledSales::nbad_index::nbad_index(const string &lb, int ix,
const string &s) : Sales::bad_index(ix, s)
{
lbl = lb;
}
LabeledSales::LabeledSales(const string &lb, int yy)
: Sales(yy)
{
label = lb;
}
LabeledSales::LabeledSales(const string &lb, int yy,
const double *gr, int n)
: Sales(yy, gr, n)
{
label = lb;
}
double LabeledSales::operator[](int i) const
{
if (i < 0 || i >= MONTHS)
throw nbad_index(Label(), i);
return Sales::operator[](i);
}
double &LabeledSales::operator[](int i)
{
if (i < 0 || i >= MONTHS)
throw nbad_index(Label(), i);
return Sales::operator[](i);
}
Code - program
// use_sales.cpp -- nested exceptions
#include <iostream>
#include "ch15_4_sales.h"
int main()
{
using std::cin;
using std::cout;
using std::endl;
double vals1[12] =
{
1220, 1100, 1122, 2212, 1232, 2334,
2884, 2393, 3302, 2922, 3002, 3544};
double vals2[12] =
{
12, 11, 22, 21, 32, 34,
28, 29, 33, 29, 32, 35};
Sales sales1(2011, vals1, 12);
LabeledSales sales2("Blogstar", 2012, vals2, 12);
cout << "First try block:\n";
try
{
int i;
cout << "Year = " << sales1.Year() << endl;
for (i = 0; i < 12; ++i)
{
cout << sales1[i] << ' ';
if (i % 6 == 5)
cout << endl;
}
cout << "Year = " << sales2.Year() << endl;
cout << "Label = " << sales2.Label() << endl;
for (i = 0; i <= 12; ++i)
{
cout << sales2[i] << ' ';
if (i % 6 == 5)
cout << endl;
}
cout << "End of try block 1.\n";
}
catch (std::exception &err)
{
cout << err.what();
LabeledSales::nbad_index *LS;
Sales::bad_index *SB;
if (LS = dynamic_cast<LabeledSales::nbad_index *>(&err))
{
cout << "Company: " << LS->label_val() << endl;
cout << "bad index: " << LS->bi_val() << endl;
}
else if(SB = dynamic_cast<Sales::bad_index* >(&err) )
{
cout << "bad index: " << SB->bi_val() << endl;
}
}
cout << "\nNext try block:\n";
try
{
sales2[2] = 37.5;
sales1[20] = 23345;
cout << "End of try block 2.\n";
}
catch (std::exception &err)
{
cout << err.what();
LabeledSales::nbad_index *LS;
Sales::bad_index *SB;
if (LS = dynamic_cast<LabeledSales::nbad_index *>(&err))
{
cout << "Company: " << LS->label_val() << endl;
cout << "bad index: " << LS->bi_val() << endl;
}
else if(SB = dynamic_cast<Sales::bad_index* >(&err) )
{
cout << "bad index: " << SB->bi_val() << endl;
}
}
cout << "done\n";
return 0;
}
/*
// sales.cpp -- Sales implementation
// use_sales.cpp -- nested exceptions
#include <iostream>
#include "sales.h"
int main()
{
using std::cin;
using std::cout;
using std::endl;
double vals1[12] =
{
1220, 1100, 1122, 2212, 1232, 2334,
2884, 2393, 3302, 2922, 3002, 3544};
double vals2[12] =
{
12, 11, 22, 21, 32, 34,
28, 29, 33, 29, 32, 35};
Sales sales1(2011, vals1, 12);
LabeledSales sales2("Blogstar", 2012, vals2, 12);
cout << "First try block:\n";
try
{
int i;
cout << "Year = " << sales1.Year() << endl;
for (i = 0; i < 12; ++i)
{
cout << sales1[i] << ' ';
if (i % 6 == 5)
cout << endl;
}
cout << "Year = " << sales2.Year() << endl;
cout << "Label = " << sales2.Label() << endl;
for (i = 0; i <= 12; ++i)
{
cout << sales2[i] << ' ';
if (i % 6 == 5)
cout << endl;
}
cout << "End of try block 1.\n";
}
catch (LabeledSales::nbad_index &bad)
{
cout << bad.what();
cout << "Company: " << bad.label_val() << endl;
cout << "bad index: " << bad.bi_val() << endl;
}
catch (Sales::bad_index &bad)
{
cout << bad.what();
cout << "bad index: " << bad.bi_val() << endl;
}
cout << "\nNext try block:\n";
try
{
sales2[2] = 37.5;
sales1[20] = 23345;
cout << "End of try block 2.\n";
}
catch (LabeledSales::nbad_index &bad)
{
cout << bad.what();
cout << "Company: " << bad.label_val() << endl;
cout << "bad index: " << bad.bi_val() << endl;
}
catch (Sales::bad_index &bad)
{
cout << bad.what();
cout << "bad index: " << bad.bi_val() << endl;
}
cout << "done\n";
return 0;
}
*/
/*
First try block:
Year = 2011
1220 1100 1122 2212 1232 2334
2884 2393 3302 2922 3002 3544
Year = 2012
Label = Blogstar
12 11 22 21 32 34
28 29 33 29 32 35
Index error in LabeledSales object
Company: Blogstar
bad index: 12
Next try block:
Index error in Sales object
bad index: 20
done
*/
Chapter 16
1 -
A palindrome is a string that is the same backward as it is forward. For example,“tot”
and “otto” are rather short palindromes.Write a program that lets a user enter a
string and that passes to a bool function a reference to the string. The function
should return true if the string is a palindrome and false otherwise. At this point,
don’t worry about complications such as capitalization, spaces, and punctuation.
That is, this simple version should reject “Otto” and “Madam, I’m Adam.” Feel free
to scan the list of string methods in Appendix F for methods to simplify the task.
Code - program
#include <iostream>
#include <string>
/// @brief Palindrome checker via simple loop (C - like)
bool fnPalindrome(const std::string &str)
{
for (int i = 0, j = str.length() - 1; i < str.length() / 2; i++, j--)
{
if (str[i] != str[j])
{
return false;
}
}
return true;
}
/// @brief Palindrome checker via reverse iterator
bool fnPalindromeRI(const std::string &str)
{
std::string strRev(str.rbegin(), str.rend()); // copy str in reverse via reverse iterator
return (str == strRev);
}
/// @brief Palindrome checker functor
struct stPalindromeFUN
{
// Overload the function call operator to check for palindromes
bool operator()(const std::string &str) const
{
std::string strRev(str.rbegin(), str.rend()); // Reverse the string
return (str == strRev); // Check if the original string is equal to its reversed version
}
};
// std::vector<std::string> words = {"racecar", "hello", "madam"};
// auto it = std::find_if(words.begin(), words.end(), palindromeChecker);
// if (it != words.end()) { std::cout << *it << " is a palindrome.\n"; }
int main()
{
std::cout << "\nWrite a word (q to quit):\t";
std::string sDataIN;
while (std::getline(std::cin, sDataIN) && sDataIN != "q")
{
std::cout << "Word " << sDataIN << " is a "
<< (fnPalindrome(sDataIN) ? "palindrome" : "not a palindrome") << "\n";
std::cout << "Word " << sDataIN << " is a "
<< (fnPalindromeRI(sDataIN) ? "palindrome" : "not a palindrome") << "\n";
stPalindromeFUN stChk;
std::cout << "Word " << sDataIN << " is a "
<< (stChk(sDataIN) ? "palindrome" : "not a palindrome") << "\n";
std::cout << "\nWrite another word: ";
}
std::cout << "\nBye!";
}
2 -
Do the same problem as given in Programming Exercise 1 but do worry about
complications such as capitalization, spaces, and punctuation. That is,“Madam, I’m
Adam” should test as a palindrome. For example, the testing function could reduce
the string to “madamimadam” and then test whether the reverse is the same. Don’t
forget the useful cctype library. You might find an STL function or two useful
although not necessary.
Code - program
#include <iostream>
#include <string>
#include <cctype>
/// @brief Palindrome checker functor
struct stPalindromeFUN
{
// Overload the function call operator to check for palindromes
bool operator()(std::string &str) const
{
// Remove non alpha characters simple loop
int i = 0;
while (i < str.length())
{
if (!isalpha(str[i]))
{
str.erase(i, 1); // remove 1 found non alphabetic data from `i` index
// the next iteration will skip one character since the index `i` has been incremented
}
else if (!islower(str[i]))
{
str[i] = tolower(str[i]);
i++; // Only increment i if we didn't erase a character
}
else
{
i++; // Only increment i if we didn't erase a character
}
}
std::cout << " reduced to word `" << str << "`";
std::string strRev(str.rbegin(), str.rend()); // Reverse the string
return (str == strRev); // Check if the original string is equal to its reversed version
}
};
// std::vector<std::string> words = {"racecar", "hello", "madam"};
// auto it = std::find_if(words.begin(), words.end(), palindromeChecker);
// if (it != words.end()) { std::cout << *it << " is a palindrome.\n"; }
/// @brief Palindrome checker functor
struct stPalindromeITR
{
// Overload the function call operator to check for palindromes
bool operator()(const std::string &org) const
{
std::string str;
// Remove non alpha characters loop with ierators
for (auto iter = org.begin(); iter != org.end(); iter++)
{
if (isalpha(*iter))
{
if (isupper(*iter))
{
str.push_back(tolower(*iter));
}
else
{
str.push_back(*iter);
}
}
}
std::cout << " reduced to word `" << str << "`";
std::string strRev(str.rbegin(), str.rend()); // Reverse the string
return (str == strRev); // Check if the original string is equal to its reversed version
}
};
int main()
{
std::cout << "\nWrite a word (q to quit):\t";
std::string sDataIN;
while (std::getline(std::cin, sDataIN) && sDataIN != "q")
{
stPalindromeITR stChi; //Constant string - invoke first
stPalindromeFUN stChk; //Changes string
std::cout << "Word " << sDataIN << " is"
<< (stChi(sDataIN) ? " is a palindrome" : " is not a palindrome") << "\n";
std::cout << "Word " << sDataIN << " is"
<< (stChk(sDataIN) ? " is a palindrome" : " is not a palindrome") << "\n";
std::cout << "\nWrite another word: ";
}
std::cout << "\nBye!";
}
3 -
Redo Listing 16.3 (hangman.cpp) so that it gets it words from a file. One approach is to use a
vector object instead of an array of string. Then you can use
push_back() to copy how ever many words are in your data file into the
vector object and use the size() member to determine the length of
the word list. Because the program should read one word at a time from the file,
you should use the >> operator rather than getline(). The file itself should contain
words separated by spaces, tabs, or new lines
Code - program
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <cctype>
#include <vector> // std::vector
#include <fstream> // std::ifstream / std::ofstream
#include <exception> // s
#include <algorithm> // std::remove
#include <sstream> // std::istringstream
using std::string;
// Method 2
// Loop to extract words using find and substr
void fnReadFileIS(std::vector<std::string> &wordList, string &strTemp)
{
int pos{};
int prev_pos{};
while ((pos = strTemp.find(',', pos)) != std::string::npos)
{
// Extract word from previous position up to current position
std::string word = strTemp.substr(prev_pos, pos - prev_pos);
// Skip empty words due to leading comma
if (!word.empty())
{
wordList.push_back(word);
}
// Update position to skip comma
prev_pos = ++pos;
}
}
// Method 1
// Use istringstream -> #include <sstream>
void fnReadFileSB(std::vector<std::string> &wordList, string &strTemp)
{
std::string word;
std::istringstream iss(strTemp);
// Extract words using getline with ',' as delimiter
while (std::getline(iss, word, ','))
{
// Skip empty words due to trailing comma
if (!word.empty())
{
wordList.push_back(word);
}
}
}
int main()
{
using std::cin;
using std::cout;
using std::endl;
using std::tolower;
std::srand(std::time(0));
std::vector<std::string> wordList;
int iNumOfWords{};
std::ifstream inFile;
inFile.open("./ch16_3_words.txt"); // OR ./ch6_3_words.txt
if (!inFile.is_open())
{
std::cerr << "Could not open the file\n"
<< "Program terminating.\n";
std::exit(EXIT_FAILURE);
}
// Read wordList from a file
int iCommas{};
int iPrvIdx{};
while (inFile.good())
{
std::string strTemp;
std::getline(inFile, strTemp); // getline
// Remove spaces if occurs
// Check ',' as divisions of words
strTemp.erase(std::remove(strTemp.begin(), strTemp.end(), ' '), strTemp.end());
if (strTemp.find(',') != std::string::npos)
{
fnReadFileSB(wordList, strTemp);
// fnReadFileIS(wordList, strTemp);
}
else
{
wordList.push_back(strTemp);
}
iPrvIdx = 0;
iCommas = 0;
++iNumOfWords;
}
char play;
cout << "Will you play a word game? <y/n> ";
cin >> play;
play = tolower(play);
cout << "\nAll possible words in game: \n";
{
int i{};
cout << "\n";
for (auto wrd : wordList)
{
if (i > 9) // print 10 words per line
{
cout << "\n";
i = 0;
}
cout << wrd << ", ";
i++;
}
}
cout << "\n\n";
while (play == 'y')
{
string target = wordList[std::rand() % iNumOfWords];
int length = target.length();
string attempt(length, '-');
string badchars;
int guesses = 6;
cout << "Guess my secret word. It has " << length
<< " letters, and you guess\n"
<< "one letter at a time. You get " << guesses
<< " wrong guesses.\n";
cout << "Your word: " << attempt << endl;
while (guesses > 0 && attempt != target)
{
char letter;
cout << "Guess a letter: ";
cin >> letter;
if (badchars.find(letter) != string::npos || attempt.find(letter) != string::npos)
{
cout << "You already guessed that. Try again.\n";
continue;
}
int loc = target.find(letter);
if (loc == string::npos)
{
cout << "Oh, bad guess!\n";
--guesses;
badchars += letter; // add to string
}
else
{
cout << "Good guess!\n";
attempt[loc] = letter;
// check if letter appears again
loc = target.find(letter, loc + 1);
while (loc != string::npos)
{
attempt[loc] = letter;
loc = target.find(letter, loc + 1);
}
}
cout << "Your word: " << attempt << endl;
if (attempt != target)
{
if (badchars.length() > 0)
cout << "Bad choices: " << badchars << endl;
cout << guesses << " bad guesses left\n";
}
}
if (guesses > 0)
cout << "That's right!\n";
else
cout << "Sorry, the word is " << target << ".\n";
cout << "Will you play another? <y/n> ";
cin >> play;
play = tolower(play);
}
cout << "Bye\n";
return 0;
}
/*
// hangman.cpp -- some string methods
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <cctype>
using std::string;
const int NUM = 26;
const string wordList[NUM] = {"apiary", "beetle", "cereal",
"danger", "ensign", "florid", "garage", "health", "insult",
"jackal", "keeper", "loaner", "manage", "nonce", "onset",
"plaid", "quilt", "remote", "stolid", "train", "useful",
"valid", "whence", "xenon", "yearn", "zippy"};
int main()
{
using std::cin;
using std::cout;
using std::endl;
using std::tolower;
std::srand(std::time(0));
char play;
cout << "Will you play a word game? <y/n> ";
cin >> play;
play = tolower(play);
while (play == 'y')
{
string target = wordList[std::rand() % NUM];
int length = target.length();
string attempt(length, '-');
string badchars;
int guesses = 6;
cout << "Guess my secret word. It has " << length
<< " letters, and you guess\n"
<< "one letter at a time. You get " << guesses
<< " wrong guesses.\n";
cout << "Your word: " << attempt << endl;
while (guesses > 0 && attempt != target)
{
char letter;
cout << "Guess a letter: ";
cin >> letter;
if (badchars.find(letter) != string::npos || attempt.find(letter) != string::npos)
{
cout << "You already guessed that. Try again.\n";
continue;
}
int loc = target.find(letter);
if (loc == string::npos)
{
cout << "Oh, bad guess!\n";
--guesses;
badchars += letter; // add to string
}
else
{
cout << "Good guess!\n";
attempt[loc] = letter;
// check if letter appears again
loc = target.find(letter, loc + 1);
while (loc != string::npos)
{
attempt[loc] = letter;
loc = target.find(letter, loc + 1);
}
}
cout << "Your word: " << attempt << endl;
if (attempt != target)
{
if (badchars.length() > 0)
cout << "Bad choices: " << badchars << endl;
cout << guesses << " bad guesses left\n";
}
}
if (guesses > 0)
cout << "That's right!\n";
else
cout << "Sorry, the word is " << target << ".\n";
cout << "Will you play another? <y/n> ";
cin >> play;
play = tolower(play);
}
cout << "Bye\n";
return 0;
}
*/
/*
Here’s a sample run of the program in Listing 16.3:
Will you play a word game? <y/n> y
Guess my secret word. It has 6 letters, and you guess
one letter at a time. You get 6 wrong guesses.
Your word: ------
Guess a letter: e
Oh, bad guess!
Your word: ------
Bad choices: e
5 bad guesses left
Guess a letter: a
Good guess!
Your word: a--a--
Bad choices: e
5 bad guesses left
Guess a letter: t
Oh, bad guess!
Your word: a--a--
Bad choices: et
4 bad guesses left
Guess a letter: r
Good guess!
Your word: a--ar-
Bad choices: et
4 bad guesses left
Guess a letter: y
Good guess!
Your word: a--ary
Bad choices: et
4 bad guesses left
Guess a letter: i
Good guess!
Your word: a-iary
Bad choices: et
4 bad guesses left
Guess a letter: p
Good guess!
Your word: apiary
That's right!
Will you play another? <y/n> n
Bye
*/
File
apiary, beetle, cereal,
danger, ensign, florid, garage, health, insult,
jackal, keeper, loaner, manage, nonce, onset,
plaid, quilt, remote, stolid, train, useful,
valid, whence, xenon, yearn, zippy,
scrape, swarm, bee, lock,
resink
transversomedial
pharyngopathy
postmineral
myelosyphilis
silverer
evincement
phrygium
punnigram
imminution
environmental
sleepify
nope
wauken
indignance
knotwort
apocodeine
escortee
dogwatch
eaglewood
unbrotherliness
mulse
dermobranchiata
typhic
poststertorous
indevout
anatomicopathologic
unimpenetrable
hoggy
urrhodin
Dioecia
unchapter
nonumbilicate
zwitterionic
apportionable
ferulic
statefulness
pharyngotonsillitis
Mimulus
recce
mutinously
reboant
marshwort
lupoid
chromatophilic
lauder
nirles
esthesiometer
semisocial
unbeing
kangaroo
takosis
inconvertibility
anesthetist
rumorproof
thoracoscopy
euphorbium
bizet
song
dolichocephali
platemaker
vesicupapular
electroforming
dilatingly
meethelp
loincloth
avowably
counterindicate
treacliness
Epigonus
airmark
polarography
precomposition
lemography
Apinage
Taal
logology
probeer
randomization
poditic
individualize
castigate
Biloculina
overscrub
koolah
weetless
erased
layery
discontinuee
anaphylatoxin
unwounded
personalism
howitzer
hexahydroxy
koku
reamer
tonguiness
microgametocyte
baba
ludefisk
4 - Write a function with an old-style interface that has this prototype:
The actual arguments should be the name of an array and the number of elements
in the array. The function should sort an array, remove duplicate values, and return a
value equal to the number of elements in the reduced array. Write the function
using STL functions. (If you decide to use the general unique() function, note that
it returns the end of the resulting range.) Test the function in a short program.
// Write a function with an old-style interface that has this prototype:
// ```cpp
// int reduce(long ar[], int n);
// ```
// The actual arguments should be the name of an array and the number of elements
// in the array.
// The function should sort an array, remove duplicate values, and return a
// value equal to the number of elements in the reduced array.
// Write the function using STL functions.
// (If you decide to use the general <code>unique()</code> function, note that
// it returns the end of the resulting range.)
// Test the function in a short program.
#include <iostream>
#include <algorithm>
#include <random> // for random_device, mt19937, uniform_int_distribution
int reduce(long ar[], int n); // Prototype
void printArr(long ar[], int n);
int main()
{
const int ARR_LEN = 50;
long lArr[ARR_LEN]{};
for (int i = 0; i < ARR_LEN; i++)
{
// Simple RNG - repeatable
// lArr[i] = (long)(std::rand() % 20);
// Advanced RNG
std::random_device rd;
std::mt19937 gen(rd());
lArr[i] = (long) std::uniform_int_distribution<>(0, 50)(gen);
}
std::cout << "\nOriginal: ";
printArr(lArr, ARR_LEN);
int iNewLen = reduce(lArr, ARR_LEN);
std::cout << "\nReduced, old length: ";
printArr(lArr, ARR_LEN);
std::cout << "\nReduced, new length: ";
printArr(lArr, iNewLen);
std::cout << "\n\nBye!";
return 0;
}
/// @brief Sort and remove duplicates in array of longs
/// @return Size of new array
int reduce(long ar[], int n)
{
std::sort(ar, ar + n);
auto itEnd = std::unique(ar, ar + n);
//distance between two pointers itEnd and ar
return itEnd - ar;
}
/// @brief Sort and remove duplicates in array of longs
/// @return Size of new array
int reduceRot(long ar[], int n) // Definition
{
// Sort
std::sort(ar, ar + n);
// printArr(ar, n);
// Remove duplicate vals
for (int i = 0, j = 0; i < n - 1; i++)
{
if (ar[i] == ar[i + 1])
{
// rotates [ar + i, ar + n) left by distance(ar + i, ar + i + 1) positions, returns the iterator pointing at *(ar + i) new home
std::rotate(ar + i, ar + i + 1, ar + n); // shift data from i, by one, set to the end
i--; // prevent going to next idx, when next val can also be the same
// Examplanary result: 0 1 2 4 5 7 9 11 12 13 14 15 16 18 1 2 4 5 7 11 15 16 18 1 2 4 7 18 1 2
// Anti-infinite-loop in case of inf repeats (can't rotate?),
// Rotate the cause to not repeat
j = (j < (n * 2)) ? j++ : 0;
!j ? i++ : 0; // if(!j){ i++; };
!j ? std::rotate(ar + i + 1, ar + i + 2, ar + n) : 0;
// if(!j){std::cout << i << ",";} // print causes
}
}
// Calculate length of new arr
for (int i = 0; i < n - 1; i++)
{
if (ar[i] > ar[i + 1])
{
return (i + 1); // return length of new arr
// i + 1, because idx start from 0
}
}
return n;
}
void printArr(long ar[], int n)
{
std::cout << "\n";
for (int i = 0; i < n; i++)
{
std::cout << ar[i] << " ";
}
}
5 - Do the same problem as described in Programming Exercise 4, except make it a template function:
Test the function in a short program, using both a long instantiation and a string
instantiation.
// Do the same problem as described in Programming Exercise 4, except make it a
// template function:
// ```cpp
// template <class T>
// int reduce(T ar[], int n);
// ```
#include <iostream>
#include <algorithm>
#include <random> // for random_device, mt19937, uniform_int_distribution
template <class T>
int reduce(T ar, int n); // Prototype
template <class T>
void printArr(T ar, int n);
int main()
{
const int ARR_LEN = 100;
long lArr[ARR_LEN]{};
for (int i = 0; i < ARR_LEN; i++)
{
// Simple RNG - repeatable
// lArr[i] = (long)(std::rand() % 20);
// Advanced RNG
std::random_device rd;
std::mt19937 gen(rd());
lArr[i] = (long)std::uniform_int_distribution<>(0, 50)(gen);
}
std::cout << "\nOriginal: ";
printArr(lArr, ARR_LEN);
int iNewLen = reduce(lArr, ARR_LEN);
std::cout << "\nReduced, old length: ";
printArr(lArr, ARR_LEN);
std::cout << "\nReduced, new length: ";
printArr(lArr, iNewLen);
std::cout << "\n\nBye!";
return 0;
}
/// @brief Sort and remove duplicates in array of longs
/// @return Size of new array
template <class T>
int reduce(T ar, int n)
{
std::sort(ar, ar + n);
auto itEnd = std::unique(ar, ar + n);
//distance between two pointers itEnd and ar
return itEnd - ar;
}
/// @brief Sort and remove duplicates in array of longs
/// @return Size of new array
template <class T>
int reduceRot(T ar, int n) // Definition
{
// Sort
std::sort(ar, ar + n);
// printArr(ar, n);
// Remove duplicate vals via rotate
for (int i = 0, j = 0; i < n - 1; i++)
{
if (ar[i] == ar[i + 1])
{
std::rotate(ar + i, ar + i + 1, ar + n); // shift data from i, by one, set to the end
i--; // prevent going to next idx, when next val can also be the same
// Anti-infinite-loop in case of inf repeats (can't rotate?),
// Rotate the cause to not repeat
j = (j < (n * 2)) ? j++ : 0;
!j ? i++ : 0; // if(!j){ i++; };
!j ? std::rotate(ar + i + 1, ar + i + 2, ar + n) : 0;
// if(!j){std::cout << i << ",";} // print causes
// Examplanary result: 0 1 2 4 5 7 9 11 12 13 14 15 16 18 1 2 4 5 7 11 15 16 18 1 2 4 7 18 1 2
}
}
// Calculate length of new arr
for (int i = 0; i < n - 1; i++)
{
if (ar[i] > ar[i + 1])
{
return (i + 1); // return length of new arr
// i + 1, because idx start from 0
}
}
return n;
}
template <class T>
void printArr(T ar, int n)
{
std::cout << "\n";
for (auto i = 0; i < n; i++)
{
std::cout << ar[i] << " ";
}
}
6 -
Redo the example shown in Listing 12.12 (bank.cpp), using the STL queue template class
instead of the Queue class described in Chapter 12.
Code - program
// bank.cpp -- using the Queue interface
// compile with queue.cpp
#include <iostream>
#include <cstdlib> // for rand() and srand()
#include <ctime> // for time()
#include <queue>
#include "ch16_6_q.h"
const int MIN_PER_HR = 60;
bool newcustomer(double x); // is there a new customer?
int main()
{
using std::cin;
using std::cout;
using std::endl;
using std::ios_base;
// setting things up
std::srand(std::time(0)); // random initializing of rand()
cout << "Case Study: Bank of Heather Automatic Teller\n";
cout << "Enter maximum size of queue: ";
int iQueueMAX;
cin >> iQueueMAX;
std::queue<Item> line;
// Queue line(qs); // line queue holds up to qs people
cout << "Enter the number of simulation hours: ";
int hours; // hours of simulation
cin >> hours;
// simulation will run 1 cycle per minute
long cyclelimit = MIN_PER_HR * hours; // # of cycles
cout << "Enter the average number of customers per hour: ";
double perhour; // average # of arrival per hour
cin >> perhour;
double min_per_cust; // average time between arrivals
min_per_cust = MIN_PER_HR / perhour;
Item temp; // new customer data
long turnaways = 0; // turned away by full queue
long customers = 0; // joined the queue
long served = 0; // served during the simulation
long sum_line = 0; // cumulative line length
int wait_time = 0; // time until autoteller is free
long line_wait = 0; // cumulative time in line
// running the simulation
for (int cycle = 0; cycle < cyclelimit; cycle++)
{
if (newcustomer(min_per_cust)) // have newcomer
{
if (line.size() >= iQueueMAX)
{
turnaways++;
}
else
{
customers++;
temp.set(cycle); // cycle = time of arrival
line.push(temp); // line.enqueue(temp); // add newcomer to line
}
}
if (wait_time <= 0 && line.size() > 0) //!line.isempty())
{
line.pop(); // line.dequeue(temp); // attend next customer
wait_time = temp.ptime(); // for wait_time minutes
line_wait += cycle - temp.when();
served++;
}
if (wait_time > 0)
wait_time--;
sum_line += line.size(); //line.queuecount();
}
// reporting results
if (customers > 0)
{
cout << "customers accepted: " << customers << endl;
cout << " customers served: " << served << endl;
cout << " turnaways: " << turnaways << endl;
cout << "average queue size: ";
cout.precision(2);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << (double)sum_line / cyclelimit << endl;
cout << " average wait time: "
<< (double)line_wait / served << " minutes\n";
}
else
cout << "No customers!\n";
cout << "Done!\n";
return 0;
}
// x = average time, in minutes, between customers
// return value is true if customer shows up this minute
bool newcustomer(double x)
{
return (std::rand() * x / RAND_MAX < 1);
}
/*
// bank.cpp -- using the Queue interface
// compile with queue.cpp
#include <iostream>
#include <cstdlib> // for rand() and srand()
#include <ctime> // for time()
#include "ch16_6_q.h"
const int MIN_PER_HR = 60;
bool newcustomer(double x); // is there a new customer?
int main()
{
using std::cin;
using std::cout;
using std::endl;
using std::ios_base;
// setting things up
std::srand(std::time(0)); // random initializing of rand()
cout << "Case Study: Bank of Heather Automatic Teller\n";
cout << "Enter maximum size of queue: ";
int qs;
cin >> qs;
Queue line(qs); // line queue holds up to qs people
cout << "Enter the number of simulation hours: ";
int hours; // hours of simulation
cin >> hours;
// simulation will run 1 cycle per minute
long cyclelimit = MIN_PER_HR * hours; // # of cycles
cout << "Enter the average number of customers per hour: ";
double perhour; // average # of arrival per hour
cin >> perhour;
double min_per_cust; // average time between arrivals
min_per_cust = MIN_PER_HR / perhour;
Item temp; // new customer data
long turnaways = 0; // turned away by full queue
long customers = 0; // joined the queue
long served = 0; // served during the simulation
long sum_line = 0; // cumulative line length
int wait_time = 0; // time until autoteller is free
long line_wait = 0; // cumulative time in line
// running the simulation
for (int cycle = 0; cycle < cyclelimit; cycle++)
{
if (newcustomer(min_per_cust)) // have newcomer
{
if (line.isfull())
turnaways++;
else
{
customers++;
temp.set(cycle); // cycle = time of arrival
line.enqueue(temp); // add newcomer to line
}
}
if (wait_time <= 0 && !line.isempty())
{
line.dequeue(temp); // attend next customer
wait_time = temp.ptime(); // for wait_time minutes
line_wait += cycle - temp.when();
served++;
}
if (wait_time > 0)
wait_time--;
sum_line += line.queuecount();
}
// reporting results
if (customers > 0)
{
cout << "customers accepted: " << customers << endl;
cout << " customers served: " << served << endl;
cout << " turnaways: " << turnaways << endl;
cout << "average queue size: ";
cout.precision(2);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << (double)sum_line / cyclelimit << endl;
cout << " average wait time: "
<< (double)line_wait / served << " minutes\n";
}
else
cout << "No customers!\n";
cout << "Done!\n";
return 0;
}
// x = average time, in minutes, between customers
// return value is true if customer shows up this minute
bool newcustomer(double x)
{
return (std::rand() * x / RAND_MAX < 1);
}
*/
/*
Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 10
Enter the number of simulation hours: 100
Enter the average number of customers per hour: 15
customers accepted: 1485
customers served: 1485
turnaways: 0
average queue size: 0.15
average wait time: 0.63 minutes
Done!
Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 10
Enter the number of simulation hours: 100
Enter the average number of customers per hour: 30
customers accepted: 2896
customers served: 2888
turnaways: 101
average queue size: 4.64
average wait time: 9.63 minutes
Done!
Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 20
Enter the number of simulation hours: 100
Enter the average number of customers per hour: 30
customers accepted: 2943
customers served: 2943
turnaways: 93
average queue size: 13.06
average wait time: 26.63 minutes
Done!
*/
7 -
A common game is the lottery card. The card has numbered spots of which a certain
number are selected at random. Write a Lotto() function that takes two arguments.
The first should be the number of spots on a lottery card, and the second
should be the number of spots selected at random. The function should return a
vector< int > object that contains, in sorted order, the numbers selected at random.
For example, you could use the function as follows:
This would assign to winners a vector that contains six numbers selected randomly
from the range 1 through 51. Note that simply using rand() doesn’t quite do the
job because it may produce duplicate values. Suggestion: Have the function create a
vector that contains all the possible values, use random_shuffle(), and then use the
beginning of the shuffled vector to obtain the values. Also write a short program
that lets you test the function.
Code - program
#include <iostream>
#include <vector>
#include <random>
#include <algorithm> // For std::count
std::vector<int> Lotto(int num_spots, int num_sel);
// Define a functor to print the winners
struct PrintWinner
{
void operator()(int winner) const
{
std::cout << winner << " ";
}
};
int main()
{
std::vector<int> winners;
winners = Lotto(51, 6);
std::cout << "\nAnd the winners of the lottery are!\n";
std::for_each(winners.begin(), winners.end(), PrintWinner());
// // Use of std::for_each to print each winner
// std::for_each(winners.begin(), winners.end(), [](const auto& winner) {
// std::cout << winner << " ";
// });
return 0;
}
/// @brief Lotto game function
/// @param num_spots number of spots on a lottery card
/// @param num_sel number of spots selected at random
/// @return vector that contains `num_sel` amount of numbers selected randomly from `1` to `num_spots`
std::vector<int> Lotto(int num_spots, int num_sel)
{
std::vector<int> _win;
{ // _rd and _gen should be only for loop
bool _uniq_val{false};
std::random_device _rd;
std::mt19937 _gen(_rd());
for (int i = 0; i < num_sel; i++)
{
_win.push_back(std::uniform_int_distribution<>(1, num_spots)(_gen));
if (!_uniq_val && _win[i] > 1) // prevents infinite loop if the same value is assigned
{
_win[i]--;
}
// Count the occurrences of the value in the vector
auto count = std::count(_win.begin(), _win.end(), _win[i]);
_uniq_val = true;
// Check if the value is unique
if (count > 1)
{
std::cout << "Not unique value occur: " << _win[i] << std::endl;
i--;
_uniq_val = false;
}
}
}
return _win;
}
8 - Mat and Pat want to invite their friends to a party. They ask you to write a program that does the following:
- Allows Mat to enter a list of his friends’ names. The names are stored in a container and then displayed in sorted order.
- Allows Pat to enter a list of her friends’ names. The names are stored in a second container and then displayed in sorted order.
- Creates a third container that merges the two lists, eliminates duplicates, and displays the contents of this container.
Code - program
#include <iostream>
#include <list>
#include <string> // getline
#include <algorithm> // sort
void enter_num(int &num)
{
while (!(std::cin >> num))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a number: ";
}
}
std::string enter_friend(std::string who, int inum)
{
std::cout << "Enter " << who << " " << inum + 1 << " friend: ";
std::string _sfriend;
// Clear any remaining newline character from the input buffer
if (std::cin.peek() == '\n')
{
std::cin.ignore(1, '\n');
}
// // broken - newline (enter) not always detected
// std::cin.clear(); // reset input
// while (std::cin.get() != '\n')
// continue; // get rid of bad input
std::getline(std::cin, _sfriend);
return _sfriend;
}
int main()
{
std::list<std::string> mat_friend_names;
std::list<std::string> pat_friend_names;
std::list<std::string> common_friend_names;
int i_mat{};
int i_pat{};
// Allows Mat to enter a list of his friends’ names. The names are stored in a container and then displayed in sorted order.
std::cout << "\n Enter number of Mat friends: ";
enter_num(i_mat);
for (int i = 0; i < i_mat; i++)
{
mat_friend_names.push_back(enter_friend("Mat", i));
}
mat_friend_names.sort();
std::cout << "\nMat friends: \n";
for (auto a : mat_friend_names)
{
std::cout << a << std::endl;
}
// Allows Pat to enter a list of her friends’ names. The names are stored in a second container and then displayed in sorted order.
std::cout << "\n Enter number of Pat friends: ";
enter_num(i_pat);
for (int i = 0; i < i_pat; i++)
{
pat_friend_names.push_back(enter_friend("Pat", i));
}
pat_friend_names.sort();
std::cout << "\nPat friends: \n";
for (auto a : pat_friend_names)
{
std::cout << a << std::endl;
}
// Third container merges the two lists, eliminates duplicates, and displays the contents of this container.
common_friend_names.merge(mat_friend_names);
common_friend_names.merge(pat_friend_names);
common_friend_names.unique();
std::cout << "\nMutual friends: \n";
for (auto a : common_friend_names)
{
std::cout << a << std::endl;
}
return 0;
}
9 - Compared to an array, a linked list features easier addition and removal of elements but is slower to sort. This raises a possibility: Perhaps it might be faster to copy a list to an array, sort the array, and copy the sorted result back to the list than to simply use the list algorithm for sorting. (But it also could use more memory.) Test the speed hypothesis with the following approach:
a. Create a large vector object vi0, using rand() to provide initial
values.
b. Create a second vector< int > object vi and a list< int > object li of the
same size as the original and initialize them to values in the original vector.
c. Time how long the program takes to sort vi using the STL sort() algorithm,
then time how long it takes to sort li using the list sort() method.
d. Reset li to the unsorted contents of vi0. Time the combined operation of
copying li to vi, sorting vi, and copying the result back to li.
To time these operations, you can use clock() from the ctime library.
As in Listing 5.14 (waiting.cpp), you can use this statement to start the first timing:
Then use the following at the end of the operation to get the elapsed time:
This is by no means a definitive test because the results will depend on a variety of factors, including available memory, whether multiprocessing is going on, and the size of the array or list. (One would expect the relative efficiency advantage of the array over the list to increase with the number of elements being sorted.) Also if you have a choice between a default build and a release build, use the release build for the measurement.With today’s speedy computers, you probably will need to use as large an array as possible to get meaningful readings.You might try, for example, 100,000 elements, 1,000,000 elements, and 10,000,000 elements.
Code - program
#include <iostream>
#include <list>
#include <vector>
#include <fstream>
#include <chrono>
#include <ctime>
#include <typeinfo>
#include <algorithm>
#define TTHOUSAND 10000
#define HTHOUSAND 100000
#define MILLION 1000000
#define BILLION 1000000000
#define TRYLLION 1000000000000
/// @brief Print data into console
/// @tparam T
/// @param data STL container ot array
/// @param what_data ID of data that will print
/// @param num_el Size of data
/// @param duration_micros Time duration that will be printed
template <typename T> // slow
void mass_print(T &data, const char *what_data, size_t num_el, size_t duration_micros = 0)
{
std::cout << what_data << " data:\n";
for (size_t i = 0; i < num_el; i++)
{
std::cout << data[i] << " ";
if (!(i % 100))
{
std::cout << "\n";
}
}
}
template <typename T>
void mass_fwrite(T &data, const char *what_data, const char *fn, size_t num_el, double duration_micros = 0)
{
std::ofstream outFile;
{
std::string merge_fn;
merge_fn = "./";
merge_fn += fn;
merge_fn += ".txt";
outFile.open(merge_fn);
}
if (!outFile.is_open())
{
std::cout << "Could not open file" << std::endl;
std::cout << "Terminate program" << std::endl;
exit(EXIT_FAILURE);
}
if (outFile.good())
{
outFile << what_data << " data asigned in: " << duration_micros << " microseconds\n";
outFile << what_data << " data asigned in: " << duration_micros / 1000.00 << " milliseconds\n";
outFile << what_data << " data asigned in: " << (long long)duration_micros / 1000.00 / 1000.00 << " seconds\n";
outFile << what_data << " data asigned in: " << ((long long)duration_micros / 1000.00 / 1000.00) / 60.00 << " minutes\n";
outFile << what_data << " data asigned in: " << (((long long)duration_micros / 1000.00 / 1000.00) / 60.00) / 60.00 << " hours\n";
outFile << "\n"
<< what_data << " data:\n";
}
// // Not adequate for List
// for (size_t i = 0; i < num_el; i++)
// {
// if (outFile.good())
// {
// outFile << data[i] << ",";
// if (!(i % 100) && i != 0)
// {
// outFile << "\n";
// }
// }
// }
// size_t i = 0;
// Iterate through the list using iterators
// for (auto it = data.begin(); it != data.end(); ++it, ++i)
// {
// if (outFile.good())
// {
// outFile << *it << ",";
// if (!(i % 100) && i != 0)
// {
// outFile << "\n";
// }
// }
// }
size_t i = 0;
for (auto a : data)
{
if (outFile.good())
{
outFile << a << ",";
if (!(i % 100) && i != 0)
{
outFile << "\n";
}
i++;
}
}
}
int main()
{
size_t num_data = MILLION;
std::vector<int> vi0; // a
std::vector<int> vi; // b
std::list<int> li; // b
// a) ------------------
// clock_t start = clock(); // ctime - calc time
auto start = std::chrono::high_resolution_clock::now(); // chrono - more precise (object) timer
for (size_t i = 0; i < num_data; i++)
{
vi0.push_back(rand() % 1000);
}
auto stop = std::chrono::high_resolution_clock::now(); // Stop the timer
auto chrono_duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start); // Calculate the duration
double duration = chrono_duration.count();
// clock_t end = clock();
// double duration = (double)(end - start) / CLOCKS_PER_SEC;
std::cout << "\nVector assignment of " << num_data
<< " points of data into " << typeid(vi0).name() << ": "
<< duration / 1000.00 << " ms";
// mass_print(vi0, vi0.size(), "Vector"); // slow
// mass_fwrite(vi0, "Vector", "ch16_9_vector", vi0.size(), duration);
// b) ------------------
vi.assign(vi0.begin(), vi0.end());
start = std::chrono::high_resolution_clock::now();
li.assign(vi0.begin(), vi0.end());
stop = std::chrono::high_resolution_clock::now();
chrono_duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
duration = chrono_duration.count();
std::cout << "\nTime to assign " << num_data
<< " points of data from " << typeid(vi0).name()
<< " into " << typeid(li).name() << ": "
<< duration / 1000.00 << " ms";
// c) ------------------ VECTOR
start = std::chrono::high_resolution_clock::now();
std::sort(vi.begin(), vi.end());
stop = std::chrono::high_resolution_clock::now();
chrono_duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
duration = chrono_duration.count();
std::cout << "\nVector sort of " << num_data
<< " points of data in " << typeid(vi).name() << ": "
<< duration / 1000.00 << " ms";
// mass_fwrite(vi, "Vector", "ch16_9_vector_sorted", vi.size(), duration);
// c) ------------------ LIST
start = std::chrono::high_resolution_clock::now();
li.sort();
stop = std::chrono::high_resolution_clock::now();
chrono_duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
duration = chrono_duration.count();
std::cout << "\nList sort of " << num_data
<< " points of data in " << typeid(li).name() << ": "
<< duration / 1000.00 << " ms";
// mass_fwrite(li, "List", "ch16_9_list_sorted", li.size(), duration);
// d) ------------------
li.assign(vi0.begin(), vi0.end());
start = std::chrono::high_resolution_clock::now();
vi.assign(li.begin(), li.end()); // copy list to vector
std::sort(vi.begin(), vi.end()); // sort vector
li.assign(vi.begin(), vi.end()); // copy back
stop = std::chrono::high_resolution_clock::now();
chrono_duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
duration = chrono_duration.count();
std::cout << "\nList of " << num_data
<< " points of data, copied to Vector, sorted and copied back to List took: "
<< duration / 1000.00 << " ms";
// mass_fwrite(li, "List", "ch16_9_task", li.size(), duration);
return 0;
}
/*
// Listing 5.14 waiting.cpp
// waiting.cpp -- using clock() in a time-delay loop
#include <iostream>
#include <ctime> // describes clock() function, clock_t type
int main()
{
using namespace std;
cout << "Enter the delay time, in seconds: ";
float secs;
cin >> secs;
clock_t delay = secs * CLOCKS_PER_SEC; // convert to clock ticks
cout << "starting\a\n";
clock_t start = clock();
while (clock() - start < delay) // wait until time elapses
; // note the semicolon
cout << "done \a\n";
return 0;
}
*/
10 - Modify Listing 16.9 (vect3.cpp) as follows:
a. Add a price member to the Review structure.
b. Instead of using a vector of Review objects to hold the input, use a vector
of shared_ptr< Review > objects. Remember that a shared_ptr has to be
initialized with a pointer returned by new.
c. Follow the input stage with a loop that allows the user the following options
for displaying books: in original order, in alphabetical order, in order of
increasing ratings, in order of decreasing ratings, in order of increasing price,
in order of decreasing price, and quitting.
Here’s one possible approach. After getting the initial input, create another vector of
shared_ptrs initialized to the original array. Define an operator<() function that
compares pointed-to structures and use it to sort the second vector so that the
shared_ptrs are in the order of the book names stored in the pointed-to objects.
Repeat the process to get vectors of shared_ptrs sorted by rating and by price.
Note that rbegin() and rend() save you the trouble of also creating vectors of
reversed order.
Code - program
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <memory> // std::shared_ptr
#include <random> // std::random_device; std::mt19937
struct Review
{
std::string title;
double price;
int rating;
};
bool operator<(const std::shared_ptr<Review> &r1, const std::shared_ptr<Review> &r2);
bool worseThan(const std::shared_ptr<Review> &r1, const std::shared_ptr<Review> &r2);
bool costmThan(const std::shared_ptr<Review> &r1, const std::shared_ptr<Review> &r2);
bool FillReview(std::shared_ptr<Review> &rr);
void ShowReview(const std::shared_ptr<Review> &rr);
void fnPrintMenu();
int main()
{
std::vector<std::shared_ptr<Review>> books;
while (true)
{
std::shared_ptr<Review> temp(new Review());
// std::shared_ptr<Review> sp = std::make_shared<Review>(); // also valid, good practice C++ 11
if (!FillReview(temp))
{
break;
}
books.push_back(temp);
}
if (!(books.size() > 0))
{
std::cout << "No entries. ";
std::cout << "Bye.\n";
return 0;
}
std::cout << "Thank you. You entered the following "
<< books.size() << " books:\n"
<< "Rating\tPrice\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
// copy vector to not modify original by sorting
std::vector<std::shared_ptr<Review>> books_cpy = books;
fnPrintMenu();
char option;
bool invoption = false;
while (std::cin >> option && option != 'q')
{
invoption = false;
switch (option)
{
case 'w':
std::cout << "In original order:\nRating\tPrice\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
break;
case 'e':
sort(books_cpy.begin(), books_cpy.end());
std::cout << "Sorted in alphabetical order:\nRating\tPrice\tBook\n";
break;
case 'r':
sort(books_cpy.begin(), books_cpy.end(), worseThan);
std::cout << "Sorted in order of increasing ratings:\nRating\tPrice\tBook\n";
break;
case 't':
sort(books_cpy.rbegin(), books_cpy.rend(), worseThan);
std::cout << "Sorted in order of decreasing ratings:\nRating\tPrice\tBook\n";
break;
case 'y':
sort(books_cpy.begin(), books_cpy.end(), costmThan);
std::cout << "Sorted in order of increasing price:\nRating\tPrice\tBook\n";
break;
case 'u':
sort(books_cpy.rbegin(), books_cpy.rend(), costmThan);
std::cout << "Sorted in order of decreasing price:\nRating\tPrice\tBook\n";
break;
default:
invoption = true;
std::cout << "\nInvalid option\n";
break;
}
if (option != 'w' && !invoption)
{
for_each(books_cpy.begin(), books_cpy.end(), ShowReview);
}
fnPrintMenu();
}
std::cout << "Bye.\n";
return 0;
}
void fnPrintMenu()
{
std::cout
<< "\nPlease select:\n"
<< "\tw) display books in original order\n"
<< "\te) display in alphabetical order\n"
<< "\tr) display in order of increasing ratings\n"
<< "\tt) display in order of decreasing ratings\n"
<< "\ty) display in order of increasing price\n"
<< "\tu) display in order of decreasing price\n"
<< "\tq) quit" << std::endl;
}
bool operator<(const std::shared_ptr<Review> &r1, const std::shared_ptr<Review> &r2)
{
if (r1->title < r2->title)
return true;
else if (r1->title == r2->title && r1->rating < r2->rating)
return true;
else
return false;
}
bool worseThan(const std::shared_ptr<Review> &r1, const std::shared_ptr<Review> &r2)
{
if (r1->rating < r2->rating)
return true;
else
return false;
}
bool costmThan(const std::shared_ptr<Review> &r1, const std::shared_ptr<Review> &r2)
{
if (r1->price < r2->price)
return true;
else
return false;
}
bool FillReview(std::shared_ptr<Review> &rr)
{
std::cout << "Enter book title (q to stop): ";
std::getline(std::cin, rr->title);
if (rr->title == "q")
return false;
std::cout << "Enter book rating: ";
std::cin >> rr->rating;
if (!std::cin)
return false;
// get rid of rest of input line
while (std::cin.get() != '\n')
continue;
std::cout << "Enter book price: ";
std::cin >> rr->price;
if (!std::cin)
return false;
// get rid of rest of input line
while (std::cin.get() != '\n')
continue;
return true;
}
void ShowReview(const std::shared_ptr<Review> &rr)
{
std::cout << rr->rating << "\t" << rr->price << "\t" << rr->title << std::endl;
}
/*
random_shuffle(books.begin(), books.end()); // random_shuffle function is deprecated in C++14 and removed in C++17. Replaced with std::shuffle
// std::shuffle function is expecting a Uniform Random Number Generator (URBG) as its third argument (rand() wont work)
// Create a random device and a generator // needs #include <random>
std::random_device rd;
std::mt19937 gen(rd()); // Mersenne Twister engine
shuffle(books.begin(), books.end(), gen);
std::random_shuffle deprecation and removal:
- Global State Dependency: std::random_shuffle might rely on the global state, using functions like rand() which is not thread-safe and can lead to less randomness in multi-threaded programs.
- Unspecified Random Number Generator (RNG): The RNG used by std::random_shuffle was not specified by the standard, which meant that its behavior could vary across different implementations, potentially leading to inconsistent results.
- Replacement by Better Alternatives: The introduction of the <random> header in C++11 provided better mechanisms for generating random numbers, including Uniform Random Number Generators (URBGs) that do not depend on global state. The std::shuffle function, introduced in C++11, takes advantage of these improvements, offering better randomness and thread safety.
- Removal in C++17: As a result of these issues, std::random_shuffle was removed entirely in C++17, and programmers were encouraged to use std::shuffle instead, which requires explicitly providing a URBG, thus ensuring consistent behavior across different implementations and environments.
*/
/*
Enter book title (quit to quit): The Cat Who Can Teach You Weight Loss
Enter book rating: 8
Enter book title (quit to quit): The Dogs of Dharma
Enter book rating: 6
Enter book title (quit to quit): The Wimps of Wonk
Enter book rating: 3
Enter book title (quit to quit): Farewell and Delete
Enter book rating: 7
Enter book title (quit to quit): quit
Thank you. You entered the following 4 ratings:
Rating Book
8 The Cat Who Can Teach You Weight Loss
6 The Dogs of Dharma
3 The Wimps of Wonk
7 Farewell and Delete
Sorted by title:
Rating Book
7 Farewell and Delete
8 The Cat Who Can Teach You Weight Loss
6 The Dogs of Dharma
3 The Wimps of Wonk
Sorted by rating:
Rating Book
3 The Wimps of Wonk
6 The Dogs of Dharma
7 Farewell and Delete
8 The Cat Who Can Teach You Weight Loss
After shuffling:
Rating Book
7 Farewell and Delete
3 The Wimps of Wonk
6 The Dogs of Dharma
8 The Cat Who Can Teach You Weight Loss
Bye.
*/
/*
// Listing 16.9 vect3.cpp
// vect3.cpp -- using STL functions
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
struct Review
{
std::string title;
int rating;
};
bool operator<(const std::shared_ptr<Review> &r1, const std::shared_ptr<Review> &r2);
bool worseThan(const std::shared_ptr<Review> &r1, const std::shared_ptr<Review> &r2);
bool FillReview(std::shared_ptr<Review> &rr);
void ShowReview(const std::shared_ptr<Review> &rr);
int main()
{
using namespace std;
vector<Review> books;
Review temp;
while (FillReview(temp))
books.push_back(temp);
if (books.size() > 0)
{
std::cout << "Thank you. You entered the following "
<< books.size() << " ratings:\n"
<< "Rating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
sort(books.begin(), books.end());
std::cout << "Sorted by title:\nRating\tPrice\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
sort(books.begin(), books.end(), worseThan);
std::cout << "Sorted by rating:\nRating\tPrice\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
random_shuffle(books.begin(), books.end());
std::cout << "After shuffling:\nRating\tPrice\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
}
else
std::cout << "No entries. ";
std::cout << "Bye.\n";
return 0;
}
bool operator<(const std::shared_ptr<Review> &r1, const std::shared_ptr<Review> &r2)
{
if (r1->title < r2->title)
return true;
else if (r1->title == r2->title && r1->rating < r2->rating)
return true;
else
return false;
}
bool worseThan(const std::shared_ptr<Review> &r1, const std::shared_ptr<Review> &r2)
{
if (r1->rating < r2->rating)
return true;
else
return false;
}
bool FillReview(std::shared_ptr<Review> &rr)
{
std::cout << "Enter book title (quit to quit): ";
std::getline(std::cin, rr->title);
if (rr->title == "quit")
return false;
std::cout << "Enter book rating: ";
std::cin >> rr->rating;
if (!std::cin)
return false;
// get rid of rest of input line
while (std::cin.get() != '\n')
continue;
return true;
}
void ShowReview(const std::shared_ptr<Review> &rr)
{
std::cout << rr->rating << "\t" << rr->title << std::endl;
}
*/
/*
Enter book title (quit to quit): The Cat Who Can Teach You Weight Loss
Enter book rating: 8
Enter book title (quit to quit): The Dogs of Dharma
Enter book rating: 6
Enter book title (quit to quit): The Wimps of Wonk
Enter book rating: 3
Enter book title (quit to quit): Farewell and Delete
Enter book rating: 7
Enter book title (quit to quit): quit
Thank you. You entered the following 4 ratings:
Rating Book
8 The Cat Who Can Teach You Weight Loss
6 The Dogs of Dharma
3 The Wimps of Wonk
7 Farewell and Delete
Sorted by title:
Rating Book
7 Farewell and Delete
8 The Cat Who Can Teach You Weight Loss
6 The Dogs of Dharma
3 The Wimps of Wonk
Sorted by rating:
Rating Book
3 The Wimps of Wonk
6 The Dogs of Dharma
7 Farewell and Delete
8 The Cat Who Can Teach You Weight Loss
After shuffling:
Rating Book
7 Farewell and Delete
3 The Wimps of Wonk
6 The Dogs of Dharma
8 The Cat Who Can Teach You Weight Loss
Bye.
*/
Chapter 17
1 -
Write a program that counts the number of characters up to the first $ in input and
that leaves the $ in the input stream.
Code - program
#include <iostream>
#include <ctime>
int main()
{
int counter{};
char ctmp;
clock_t start = clock();
std::cout << "\nYou can write anything till the `$` character... try it!" << std::endl;
// while ((ctmp = std::cin.get()) != '$') // it wont work if the first character will be $ directly after newline, because std::cin.get() does not skip newline character,
std::cin.get(ctmp);
while (ctmp != '$')
{
counter++;
// std::cin.get(ctmp); // Reads a single character from the input stream and stores it in ctmp. It wont skip any character (including whitespaces)
std::cin >> ctmp; // It skips any leading whitespace (spaces, newlines, tabs) - int this case for counting
}
std::cout << "\nYou have killed this program with " << ctmp << std::endl
<< "It counted " << counter << " characters before " << ctmp << " and the next character would be " << (char) std::cin.get() << std::endl
<< "It lived only for " << (double)(clock() - start) / CLOCKS_PER_SEC << " seconds!";
std::cout << "\n\nBye!";
return 0;
}
2 - Write a program that copies your keyboard input (up to the simulated end-of-file) to a file named on the command line.
Code - program
#include <iostream>
#include <fstream> // ofstream
#include <string>
#include <sstream> // ostringstream
#include <cstring>
int main(int argc, char **argv)
{
if (argc == 1)
{
std::cerr << "\nNo file argument!" << std::endl;
std::cerr << "Exit program!" << std::endl;
return 1; // Exit failure - no file
}
else if (argc > 2)
{
std::cerr << "\nToo many arguments!" << std::endl;
std::cerr << "Enter only filename as 1'st argument to write data into." << std::endl;
return 2;
}
std::ostringstream oss_buff; // more efficient than string, because it does not create temporary objects
std::string line;
std::ofstream outFile;
outFile.open(argv[1]);
if (!outFile.is_open())
{
std::cerr << "Error: file could not be opened" << std::endl;
return 3;
}
std::cout << "\nData from keyboard will be written to the file!" << std::endl;
std::cout << "Write 'exit' in new line to stop the program." << std::endl;
while (true)
{
std::getline(std::cin, line);
if (line == "exit")
{
break; // Exit the loop when "exit" is entered
}
oss_buff << line << '\n'; // Append the line and a newline character to the ostringstream
outFile << line << '\n'; // Append the line in opened file
}
outFile.close();
std::cout << "\nYou have written:" << std::endl;
std::cout << oss_buff.str(); // Display the accumulated data
std::cout << "\nInto file:" << (std::string)argv[1] << std::endl; // convert to string and display whole argument
// C - like simpler implementation of line above
/*
int len = strlen(argv[1]);
for (size_t i = 0; i < len; i++)
{
std::cout << argv[1][i];
}
std::cout << std::endl;
*/
return 0;
}
3 - Write a program that copies one file to another. Have the program take the filenames from the command line. Have the program report if it cannot open a file.
Code - program
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
int main(int argc, char **argv)
{
if (argc == 1)
{
std::cerr << "\nNo file arguments!" << std::endl;
std::cerr << "Exit program!" << std::endl;
return 1; // Exit failure - no file
}
else if (argc != 3)
{
std::cerr << "\nIncorrect number of arguments!" << std::endl;
std::cerr << "Enter filename to copy data from as 1'st argument" << std::endl;
std::cerr << "and 2'nd argument the filename to write data into." << std::endl;
return 2;
}
// std::ostringstream oss_linebuff; // more efficient than string, because it does not create temporary objects
std::ifstream inFile;
inFile.open(argv[1]);
if (!inFile.is_open())
{
std::cerr << "Error: 1'st file could not be opened" << std::endl;
return 3;
}
std::ofstream outFile;
outFile.open(argv[2]);
if (!outFile.is_open())
{
std::cerr << "Error: 2'nd file could not be opened" << std::endl;
return 3;
}
std::cout << "\nCopying "
<< (std::string)argv[1] << " file contents into "
<< (std::string)argv[2] << std::endl;
// copy character by character - least efficient method <==============
/*
char tmp;
while (inFile.get(tmp))
{
outFile.put(tmp);
}
*/
// More efficient - https://www.geeksforgeeks.org/cpp-program-to-copy-one-file-into-another-file/ <==============
/*
std::string tmpLine;
while (getline(inFile, tmpLine)) {
outFile << tmpLine << "\n";
}
*/
// Approach below is more efficient than copying one character/line at a time, <==============
// especially when dealing with larger files.
/*
const size_t bufferSize = 1024 * 1024; // 1 MB buffer
std::vector<char> buffer(bufferSize);
while (inFile.read(buffer.data(), bufferSize)) {
outFile.write(buffer.data(), inFile.gcount());
}
// Write any remaining data
outFile.write(buffer.data(), inFile.gcount());
*/
// Simple fast BINARY copy <==============
/*
std::ifstream inFile(argv[1], std::ios::binary);
std::ofstream outFile(argv[2], std::ios::binary);
outFile << inFile.rdbuf();
*/
// simplest and (one of the) fastest way using stream buffer in ios library <==============
// https://cplusplus.com/reference/ios/ios/rdbuf/
// https://stackoverflow.com/questions/10195343/copy-a-file-in-a-sane-safe-and-efficient-way
outFile << inFile.rdbuf();
std::cout << "\nDone!\nExit program!";
return 0;
}
4 - Write a program that opens two text files for input and one for output.The program should concatenate the corresponding lines of the input files, use a space as a separator, and write the results to the output file. If one file is shorter than the other, the remaining lines in the longer file should also be copied to the output file. For example, suppose the first input file has these contents:
And suppose the second input file has these contents:
The resulting file would have these contents:
Code - program
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
int main(int argc, char **argv)
{
if (argc == 1)
{
std::cerr << "\nNo file arguments!" << std::endl;
std::cerr << "Exit program!" << std::endl;
return 1; // Exit failure - no file
}
else if (argc != 4)
{
std::cerr << "\nIncorrect number of arguments!" << std::endl;
std::cerr << "Enter filename to copy data from as 1'st and 2'nd argument" << std::endl;
std::cerr << "3'rd argument should be the filename to write data into." << std::endl;
return 2;
}
std::vector<std::string> dataVect;
std::ifstream inFile[2];
for (int i = 0; i < 2; i++)
{
inFile[i].open(argv[i + 1]);
if (!inFile[i].is_open())
{
std::cerr << "Error: " << i << " input file could not be opened" << std::endl;
return 3;
}
}
std::ofstream outFile;
outFile.open(argv[3], std::ios_base::out | std::ios_base::app);
if (!outFile.is_open())
{
std::cerr << "Error: output file could not be opened" << std::endl;
return 3;
}
std::cout << "\nCopying "
<< (std::string)argv[1] << " and " << (std::string)argv[2] << " file contents into "
<< (std::string)argv[3] << std::endl;
std::string tmpLine;
int cntData[2]{};
// Assign data t ovector from 1'st file
while (std::getline(inFile[0], tmpLine))
{
dataVect.push_back(tmpLine);
cntData[0]++;
}
// Append data to vector from 2'nd file
while (std::getline(inFile[1], tmpLine))
{
if (cntData[1] > cntData[0])
{
dataVect.push_back(tmpLine);
}
else
{
dataVect[cntData[1]] += " ";
dataVect[cntData[1]] += tmpLine;
cntData[1]++;
}
}
// Write data into file
for (auto &&i : dataVect)
{
outFile << i << "\n";
}
for (int i = 0; i < 2; i++)
{
inFile[i].close();
}
outFile.close();
std::cout << "\nDone!" << std::endl;
return 0;
}
5 - Mat and Pat want to invite their friends to a party, much as they did in Programming Exercise 8 in Chapter 16, except now they want a program that uses files. They have asked you to write a program that does the following:
- Reads a list of Mat’s friends’ names from a text file called
mat.dat, which lists one friend per line. The names are stored in a container and then displayed in sorted order. - Reads a list of Pat’s friends’ names from a text file called
pat.dat, which lists one friend per line. The names are stored in a container and then displayed in sorted order. - Merges the two lists, eliminating duplicates and stores the result in the file matnpat.dat, one friend per line.
Code - program
#include <iostream>
#include <list>
#include <vector>
#include <string> // getline
#include <algorithm> // sort
#include <fstream>
int read_friends(std::list<std::string> &rd, std::string const &fn)
{
std::ifstream ifile(fn);
std::string tmpLine;
if (!ifile.is_open())
{
std::cerr << "\nError opening file";
return 1;
}
while (std::getline(ifile, tmpLine))
{
rd.push_back(tmpLine);
}
ifile.close();
return 0;
}
int write_friends(std::list<std::string> &rd, std::string const &fn)
{
std::ofstream ofile(fn);
if (!ofile.is_open())
{
std::cerr << "\nError opening file";
return 1;
}
for (auto &&i : rd)
{
ofile << i << "\n";
}
ofile.close();
return 0;
}
int main()
{
std::list<std::string> matFriendNames;
std::list<std::string> patFriendNames;
std::list<std::string> commonFriendNames;
std::vector<std::string> fileNames{
"ch17_5_mat.dat", "ch17_5_pat.dat", "ch17_5_mrg.dat"};
// Read, sort and display Mat friends
read_friends(matFriendNames, fileNames[0]);
matFriendNames.sort();
std::cout << "\nMat friends: \n";
for (auto a : matFriendNames)
{
std::cout << a << std::endl;
}
// Read, sort and display Pat friends
read_friends(patFriendNames, fileNames[1]);
patFriendNames.sort();
std::cout << "\nPat friends: \n";
for (auto a : patFriendNames)
{
std::cout << a << std::endl;
}
// Merge, remove duplicates, display and write to file
commonFriendNames.merge(matFriendNames);
commonFriendNames.merge(patFriendNames);
commonFriendNames.unique();
std::cout << "\nMutual friends: \n";
for (auto a : commonFriendNames)
{
std::cout << a << std::endl;
}
write_friends(commonFriendNames, fileNames[2]);
std::cout << "\nDone!";
return 0;
}
6 - Consider the class definitions of Programming Exercise 5 in Chapter 14,“Reusing Code in C++”. If you haven’t yet done that exercise, do so now. Then do the following:
Write a program that uses standard C++ I/O and file I/O in conjunction with data of types employee, manager, fink, and highfink, as defined in Programming Exercise 5 in Chapter 14. The program should be along the general lines of Listing 17.17 in that it should let you add new data to a file. The first time through, the program should solicit data from the user, show all the entries, and save the information in a file. On subsequent uses, the program should first read and display the file data, let the user add data, and show all the data. One difference is that data should be handled by an array of pointers to type employee.That way, a pointer can point to an employee object or to objects of any of the three derived types. Keep the array small to facilitate checking the program; for example, you might limit the array to 10 elements:
For keyboard entry, the program should use a menu to offer the user the choice of
which type of object to create.The menu should use a switch to use new to create
an object of the desired type and to assign the object’s address to a pointer in the pc
array.Then that object can use the virtual setall() function to elicit the appropriate
data from the user:
To save the data to a file, devise a virtual writeall() function for that purpose:
Note
Use text I/O, not binary I/O, for Programming Exercise 6. (Unfortunately, virtual objects include pointers to tables of pointers to virtual functions, andwrite() copies this information
to a file. An object filled by using read() from the file gets weird values for the function
pointers, which really messes up the behavior of virtual functions.) Use a newline character
to separate each data field from the next; this makes it easier to identify fields on input. Or
you could still use binary I/O, but not write objects as a whole. Instead, you could provide
class methods that apply the write() and read() functions to each class member individually
rather than to the object as a whole. That way, the program could save just the
intended data to a file.
The tricky part is recovering the data from the file. The problem is, how can the
program know whether the next item to be recovered is an employee object, a
manager object, a fink type, or a highfink type? One approach is, when writing
the data for an object to a file, precede the data with an integer that indicates the
type of object to follow.Then, on file input, the program can read the integer and
then use switch to create the appropriate object to receive the data:
enum classkind
{
Employee,
Manager,
Fink,
Highfink
}; // in class header
... int classtype;
while ((fin >> classtype).get(ch)) // newline separates int from data
{
switch (classtype)
{
case Employee:
pc[i] = new employee;
: break;
Then you can use the pointer to invoke a virtual getall() function to read the
information:
Code - program
#include <iostream>
#include <fstream>
#include "ch17_6_emp.h"
using namespace std;
void printMenu();
int countData(ifstream &fin, string fn);
const int MAX = 10; // no more than 10 objects
int main(void)
{
int classtype{};
abstr_emp *pc[MAX];
ifstream fin;
ofstream fout;
string fname{"ch17_6_emp.dat"};
fin.open(fname);
if (fin.good() && fin.is_open())
{
char ch;
int i{};
cout << "File found, loading data." << '\n';
while ((fin >> classtype).get(ch))
{
switch (classtype)
{
case Employee:
pc[i] = new employee();
break;
case Manager:
pc[i] = new manager();
break;
case Fink:
pc[i] = new fink();
break;
case Highfink:
pc[i] = new highfink();
break;
default:
cout << "\nErroneous input in file..\n";
break;
}
pc[i]->ReadAll(fin);
pc[i]->ShowAll();
i++;
if (i >= MAX)
{
cout << "\nMaximum number of data reached!\n";
break;
}
}
fin.close();
}
else if (!fin.good())
{
cout << "File don't exist!" << endl;
}
else
{
cerr << "Couldn't open file" << '\n';
exit(EXIT_FAILURE);
}
fout.open(fname, ios::out | ios::app);
if (fout.is_open())
{
char ch;
int i{};
bool wi{false};
bool qm{false};
bool fst_app{false}; // first time appending
printMenu();
while ((cin >> classtype).get(ch))
{
wi = false;
if (!fst_app && classtype < 4)
{
fst_app = true;
fout << '\n';
}
switch (classtype)
{
case Employee:
fout << Employee << endl;
pc[i] = new employee();
break;
case Manager:
fout << Manager << endl;
pc[i] = new manager();
break;
case Fink:
fout << Fink << endl;
pc[i] = new fink();
break;
case Highfink:
fout << Highfink << endl;
pc[i] = new highfink();
break;
case 9:
cout << "\nBye!\n";
qm = true;
break;
default:
wi = true;
cout << "\nWrong input.\n";
while (cin.get() != '\n')
{
continue;
}
break;
}
if (qm)
{
break;
}
if (!wi)
{
pc[i]->SetAll();
pc[i]->WriteAll(fout);
pc[i]->ShowAll();
i++;
if (i >= MAX)
{
cout << "\nMaximum number of data reached!\n";
break;
}
}
printMenu();
}
fout.close();
}
else
{
cerr << "Couldn't open/make file" << '\n';
exit(EXIT_FAILURE);
}
countData(fin, fname);
fin.clear();
fin.open(fname);
if (fin.good() && fin.is_open())
{
char ch;
int i{};
cout << "Current data in file:" << endl;
while ((fin >> classtype).get(ch))
{
switch (classtype)
{
case Employee:
pc[i] = new employee();
break;
case Manager:
pc[i] = new manager();
break;
case Fink:
pc[i] = new fink();
break;
case Highfink:
pc[i] = new highfink();
break;
default:
cout << "\nErroneous input in file..\n";
break;
}
pc[i]->ReadAll(fin);
pc[i]->ShowAll();
i++;
}
fin.close();
}
else if (!fin.good())
{
cerr << "File don't exist!" << endl;
exit(EXIT_FAILURE);
}
else
{
cerr << "Couldn't open file" << '\n';
exit(EXIT_FAILURE);
}
cout << "\nDone!" << endl;
return 0;
}
void printMenu()
{
cout << "\nSelect type of data to write and save:\n"
<< Employee << ") Employee\t" << Manager << ") Manager\n"
<< Fink << ") Fink\t\t" << Highfink << ") High Fink\n"
<< "9) Quit Write-Menu\n";
}
// Listing 17.17 count.cpp // without arg
int countData(ifstream &fin, string fn)
{
long count;
long total = 0;
char ch;
fin.open(fn);
if (!fin.is_open())
{
cerr << "Could not open " << fn << endl;
fin.clear();
return 1;
}
count = 0;
while (fin.get(ch))
count++;
cout << count << " characters in " << fn << endl;
total += count;
fin.clear(); // needed for some implementations
fin.close(); // disconnect file
return 0;
}
Code - classes prototypes
// emp.h -- header file for abstr_emp class and children
#ifndef _EMP_H_
#define _EMP_H_
#include <iostream>
#include <string>
#include <fstream>
enum classkind
{
Employee,
Manager,
Fink,
Highfink
}; // in class header
class abstr_emp
{
private:
std::string fname; // abstr_emp's first name
std::string lname; // abstr_emp's last name
std::string job;
public:
abstr_emp();
abstr_emp(const std::string &fn, const std::string &ln, const std::string &j);
virtual void ShowAll() const; // labels and shows all data
virtual void SetAll(); // prompts user for values
virtual void ReadAll(std::ifstream &fi);
virtual void WriteAll(std::ofstream &fo);
friend std::ostream &operator<<(std::ostream &os, const abstr_emp &e);
// just displays first and last name
virtual ~abstr_emp() = 0; // virtual base class
};
class employee : public abstr_emp
{
public:
employee();
employee(const std::string &fn, const std::string &ln, const std::string &j);
virtual void ShowAll() const;
virtual void SetAll();
virtual void ReadAll(std::ifstream &fi);
virtual void WriteAll(std::ofstream &fo);
};
class manager : virtual public abstr_emp
{
private:
int inchargeof; // number of abstr_emps managed
protected:
int InChargeOf() const { return inchargeof; } // output
int &InChargeOf() { return inchargeof; } // input
public:
manager();
manager(const std::string &fn, const std::string &ln,
const std::string &j, int ico = 0);
manager(const abstr_emp &e, int ico);
manager(const manager &m);
virtual void ShowAll() const;
virtual void SetAll();
virtual void ReadAll(std::ifstream &fi);
virtual void WriteAll(std::ofstream &fo);
};
class fink : virtual public abstr_emp
{
private:
std::string reportsto; // to whom fink reports
protected:
const std::string ReportsTo() const { return reportsto; }
std::string &ReportsTo() { return reportsto; }
void setReportsTo(std::string rt) { reportsto = rt; }
public:
fink();
fink(const std::string &fn, const std::string &ln,
const std::string &j, const std::string &rpo);
fink(const abstr_emp &e, const std::string &rpo);
fink(const fink &e);
virtual void ShowAll() const;
virtual void SetAll();
virtual void ReadAll(std::ifstream &fi);
virtual void WriteAll(std::ofstream &fo);
};
class highfink : public manager, public fink // management fink
{
public:
highfink();
highfink(const std::string &fn, const std::string &ln,
const std::string &j, const std::string &rpo,
int ico);
highfink(const abstr_emp &e, const std::string &rpo, int ico);
highfink(const fink &f, int ico);
highfink(const manager &m, const std::string &rpo);
highfink(const highfink &h);
virtual void ShowAll() const;
virtual void SetAll();
virtual void ReadAll(std::ifstream &fi);
virtual void WriteAll(std::ofstream &fo);
};
#endif
Code - classes methods
#include "ch17_6_emp.h"
/// abstr_emp /// --------------------------------------
abstr_emp::abstr_emp()
{
fname = "-";
lname = "-";
job = "-";
}
abstr_emp::abstr_emp(const std::string &fn, const std::string &ln, const std::string &j)
{
fname = fn;
lname = ln;
job = j;
}
void abstr_emp::ShowAll() const
{
std::cout << std::endl;
std::cout << "First name: " << fname;
std::cout << std::endl;
std::cout << "Last name: " << lname;
std::cout << std::endl;
std::cout << "Profession: " << job;
std::cout << std::endl;
}
void abstr_emp::SetAll()
{
std::cout << std::endl;
std::cout << "Enter the first name: ";
std::getline(std::cin, fname);
std::cout << "Enter the last name: ";
std::getline(std::cin, lname);
std::cout << "Enter the profession: ";
std::getline(std::cin, job);
}
void abstr_emp::ReadAll(std::ifstream &fi)
{
std::getline(fi, fname);
std::getline(fi, lname);
std::getline(fi, job);
}
void abstr_emp::WriteAll(std::ofstream &fo)
{
fo << fname << std::endl;
fo << lname << std::endl;
fo << job << std::endl;
}
std::ostream &operator<<(std::ostream &os, const abstr_emp &e)
{
os << e.fname << " " << e.lname << ", " << e.job;
return os;
}
abstr_emp::~abstr_emp()
{
std::cout << std::endl;
std::cout << "\tEliminated: " << fname << " " << lname;
}
/// employee /// --------------------------------------
employee::employee() : abstr_emp()
{
}
employee::employee(const std::string &fn, const std::string &ln, const std::string &j) : abstr_emp(fn, ln, j)
{
}
void employee::ShowAll() const
{
abstr_emp::ShowAll();
}
void employee::SetAll()
{
abstr_emp::SetAll();
}
void employee::ReadAll(std::ifstream &fi)
{
abstr_emp::ReadAll(fi);
}
void employee::WriteAll(std::ofstream &fo)
{
abstr_emp::WriteAll(fo);
}
/// manager /// --------------------------------------
manager::manager() : abstr_emp()
{
inchargeof = 0;
}
manager::manager(const std::string &fn, const std::string &ln,
const std::string &j, int ico) : abstr_emp(fn, ln, j)
{
inchargeof = ico;
}
// Base class constructor is automatically invoked unless another
// constructor is explicitly called in the derived class for abstr_emp(e) - so called shallow copy
manager::manager(const abstr_emp &e, int ico) : abstr_emp(e)
{
inchargeof = ico;
}
manager::manager(const manager &m) : abstr_emp(m)
{
inchargeof = m.InChargeOf();
}
void manager::ShowAll() const
{
abstr_emp::ShowAll();
std::cout << std::endl;
std::cout << "Manager is in charge of: " << inchargeof << " people";
std::cout << std::endl;
}
void manager::SetAll()
{
abstr_emp::SetAll();
std::cout << "Enter the amount of people manager will be in charge of: ";
while (!(std::cin >> inchargeof || inchargeof <= 0))
{
std::cin.clear(); // reset input
while (std::cin.get() != '\n')
continue; // get rid of bad input
std::cout << "Please enter a positive number: ";
}
std::cin.clear(); // reset input after putting in data
while (std::cin.get() != '\n')
continue; // get rid of bad input
}
void manager::ReadAll(std::ifstream &fi)
{
abstr_emp::ReadAll(fi);
fi >> inchargeof;
}
void manager::WriteAll(std::ofstream &fo)
{
abstr_emp::WriteAll(fo);
fo << inchargeof << std::endl;
}
/// fink /// --------------------------------------
fink::fink() : abstr_emp()
{
reportsto = "-";
}
fink::fink(const std::string &fn, const std::string &ln,
const std::string &j, const std::string &rpo) : abstr_emp(fn, ln, j)
{
reportsto = rpo;
}
fink::fink(const abstr_emp &e, const std::string &rpo) : abstr_emp(e)
{
reportsto = rpo;
}
fink::fink(const fink &e) : abstr_emp(e)
{
reportsto = e.reportsto;
// reportsto = e.ReportsTo();
// reportsto = this->ReportsTo(); // ??
}
void fink::ShowAll() const
{
abstr_emp::ShowAll();
std::cout << "Fink reports to: " << reportsto;
std::cout << std::endl;
}
void fink::SetAll()
{
abstr_emp::SetAll();
std::cout << "Enter superior to reports to: ";
std::getline(std::cin, reportsto);
}
void fink::ReadAll(std::ifstream &fi)
{
abstr_emp::ReadAll(fi);
std::getline(fi, reportsto);
}
void fink::WriteAll(std::ofstream &fo)
{
abstr_emp::WriteAll(fo);
fo << reportsto << std::endl;
}
/// high fink /// --------------------------------------
highfink::highfink() : abstr_emp(), manager(), fink()
{
}
highfink::highfink(const std::string &fn, const std::string &ln,
const std::string &j, const std::string &rpo,
int ico) : abstr_emp(fn, ln, j), manager(fn, ln, j, ico), fink(fn, ln, j, rpo)
{
}
highfink::highfink(const abstr_emp &e, const std::string &rpo, int ico) : abstr_emp(e), manager(e, ico), fink(e, rpo)
{
}
highfink::highfink(const fink &f, int ico) : abstr_emp(f), manager(f, ico), fink(f)
{
}
highfink::highfink(const manager &m, const std::string &rpo) : abstr_emp(m), manager(m), fink(m, rpo)
{
}
highfink::highfink(const highfink &h) : abstr_emp(h), manager(h), fink(h)
{
}
void highfink::ShowAll() const
{
manager::ShowAll();
std::cout << std::endl;
std::cout << "High fink reports to: " << fink::ReportsTo();
std::cout << std::endl;
}
void highfink::SetAll()
{
abstr_emp::SetAll();
std::cout << "In charge of: ";
std::cin >> manager::InChargeOf();
std::cin.ignore();
std::cout << "Reports to: ";
getline(std::cin, fink::ReportsTo());
}
void highfink::ReadAll(std::ifstream &fi)
{
abstr_emp::ReadAll(fi);
fi >> manager::InChargeOf();
fi.ignore(); // necessary for correct work of getline !!!
getline(fi, fink::ReportsTo());
}
void highfink::WriteAll(std::ofstream &fo)
{
abstr_emp::WriteAll(fo);
fo << manager::InChargeOf() << std::endl;
fo << fink::ReportsTo() << std::endl;
}
7 -
Here is part of a program that reads keyboard input into a vector of string objects,
stores the string contents (not the objects) in a file, and then copies the file contents
back into a vector of string objects:
int main()
{
using namespace std;
vector<string> vostr;
string temp;
// acquire strings
cout << "Enter strings (empty line to quit):\n";
while (getline(cin, temp) && temp[0] != '\0')
vostr.push_back(temp);
cout << "Here is your input.\n";
for_each(vostr.begin(), vostr.end(), ShowStr);
// store in a file
ofstream fout("strings.dat", ios_base::out | ios_base::binary);
for_each(vostr.begin(), vostr.end(), Store(fout));
fout.close();
// recover file contents
vector<string> vistr;
ifstream fin("strings.dat", ios_base::in | ios_base::binary);
if (!fin.is_open())
{
cerr << "Could not open file for input.\n";
exit(EXIT_FAILURE);
}
GetStrs(fin, vistr);
cout << "\nHere are the strings read from the file:\n";
for_each(vistr.begin(), vistr.end(), ShowStr);
return 0;
}
Note that the file is opened in binary format and that the intention is that I/O be
accomplished with read() and write(). Quite a bit remains to be done:
-
Write a
void ShowStr(const string &)function that displays a string object followed by a newline character. -
Write a
Storefunctor that writes string information to a file.The Store constructor should specify anifstreamobject, and the overloadedoperator()(const string &)should indicate the string to write. A workable plan is to first write the string’s size to the file and then write the string contents. For example, if len holds the string size, you could use this:os.write((char *)&len, sizeof(std::size_t)); // store length os.write(s.data(), len); // store charactersThe
data()member returns a pointer to an array that holds the characters in the string. It’s similar to thec_str()member except that the latter appends a null character. -
Write a
GetStrs()function that recovers information from the file. It can useread()to obtain the size of a string and then use a loop to read that many characters from the file, appending them to an initially empty temporary string. Because a string’s data is private, you have to use a class method to get data into the string rather than read directly into it.
Code - program
#include <iostream>
#include <string>
#include <vector>
#include <algorithm> // for_each
#include <fstream>
using namespace std;
// Store functor // functor that writes string information to a file.
class Store
{
ostream &os; // ofstream &os; // also correct -
public:
Store(ofstream &o) : os(o) {}
// Binary output
void operator()(const string &str)
{
size_t len = str.size();
os.write((char *)&len, sizeof(size_t));
os.write(str.data(), len);
}
};
void GetStrs(std::ifstream &is, std::vector<std::string> &vstr) {
// The function reads the length of each string as a size_t from the binary file
// in any other cases there can be artefacts, because it was written in size_t
size_t len;
char ch;
std::string temp;
while (is.read((char*)(&len), sizeof(len))) {
temp.clear();
// reads len characters into a temporary string temp
for (size_t i = 0; i < len; ++i) {
if (is.read(&ch, 1)) { // byte after byte
temp += ch;
} else {
break;
}
}
if (is) { // Check if the stream is still good
vstr.push_back(temp);
}
}
}
// function that displays a string object followed by a newline character.
void ShowStr(string &s)
{
cout << s << "\n";
}
int main()
{
using namespace std;
vector<string> vostr;
string temp;
// acquire strings
cout << "Enter strings (empty line to quit):\n";
while (getline(cin, temp) && temp[0] != '\0')
vostr.push_back(temp);
cout << "Here is your input.\n";
for_each(vostr.begin(), vostr.end(), ShowStr);
// store in a file
ofstream fout("strings.dat", ios_base::out | ios_base::binary);
for_each(vostr.begin(), vostr.end(), Store(fout));
fout.close();
// recover file contents
vector<string> vistr;
ifstream fin("strings.dat", ios_base::in | ios_base::binary);
if (!fin.is_open())
{
cerr << "Could not open file for input.\n";
exit(EXIT_FAILURE);
}
GetStrs(fin, vistr);
cout << "\nHere are the strings read from the file:\n";
for_each(vistr.begin(), vistr.end(), ShowStr);
return 0;
}
Chapter 18
1 - Here is part of a short program:
int main()
{
using namespace std;
// list of double deduced from list contents
auto q = average_list({15.4, 10.7, 9.0});
cout << q << endl;
// list of int deduced from list contents
cout << average_list({20, 30, 19, 17, 45, 38}) << endl;
// forced list of double
auto ad = average_list<double>({'A', 70, 65.33});
cout << ad << endl;
return 0;
}
Complete the program by supplying the average_list() function. It should be a
template function, with the type parameter being used to specify the kind of
initialized_list template to be used as the function parameter and also to give
the function return type.
Code - program
#include <iostream>
#include <initializer_list>
template <typename T>
T average_list(std::initializer_list<T> tin)
{
T sum{};
int i{};
for(auto a : tin)
{
sum += a;
i++;
}
// Different method
/*
for (auto p = tin.begin(); p != tin.end(); p++)
{
sum += *p;
i++;
}
*/
return sum / i;
}
int main()
{
using namespace std;
// list of double deduced from list contents
auto q = average_list({15.4, 10.7, 9.0});
cout << q << endl;
// list of int deduced from list contents
cout << average_list({20, 30, 19, 17, 45, 38}) << endl;
// forced list of double
auto ad = average_list<double>({'A', 70, 65.33});
cout << ad << endl;
return 0;
}
2 -
Here is declaration for the Cpmv class:
class Cpmv
{
public:
struct Info
{
std::string qcode;
std::string zcode;
};
private:
Info *pi;
public:
Cpmv();
Cpmv(std::string q, std::string z);
Cpmv(const Cpmv &cp);
Cpmv(Cpmv &&mv);
~Cpmv();
Cpmv &operator=(const Cpmv &cp);
Cpmv &operator=(Cpmv &&mv);
Cpmv operator+(const Cpmv &obj) const;
void Display() const;
};
The operator+() function should create an object whose qcode and zcode members
concatenate the corresponding members of the operands. Provide code that
implements move semantics for the move constructor and the move assignment
operator. Write a program that uses all the methods. For testing purposes, make the
various methods verbose so that you can see when they are used.
Code - class
#ifndef _CMPV_H_
#define _CMPV_H_
#include <iostream>
class Cpmv
{
public:
struct Info
{
std::string qcode;
std::string zcode;
};
private:
Info *pi;
public:
Cpmv();
Cpmv(std::string q, std::string z);
Cpmv(const Cpmv &cp);
Cpmv(Cpmv &&mv);
~Cpmv();
Cpmv &operator=(const Cpmv &cp);
Cpmv &operator=(Cpmv &&mv);
Cpmv operator+(const Cpmv &obj) const;
void Display() const;
};
#endif
3 -
Write and test a variadic template function sum_values() that accepts an arbitrarily
long list of arguments with numeric values (they can be a mixture of types) and
returns the sum as a long double value
Code - program
4 -
Redo Listing 16.5 using lambdas. In particular, replace the outint() function with
a named lambda and replace the two uses of a functor with two anonymous lambda
expressions.
Notes
The good() method in C++ is used to check the state of a stream object.
It returns true if none of the stream's error state flags (eofbit, failbit, badbit) are set. These flags indicate end-of-file, a logical error
on the stream, and a reading or writing error on the stream, respectively. If any of these flags are set, the good() method returns false.
It's a good practice to use good() or similar methods (is_open(), fail(), etc.) before writing data into a file.
These methods allow you to check the state of your file stream and ensure that it's safe to proceed with writing data.
If you don't check the state of the file stream before writing, you might encounter errors or exceptions, especially if the file doesn't exist, can't
be accessed, or has been corrupted.
Debug in VSCode
PATH: .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/exercises/chapter11/ch11_2.out",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"additionalSOLibSearchPath": "/path/to/symbols;/another/path/to/symbols"
}
]
}
PATH: .vscode/tasks.json
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++-11 build active file",
"command": "/usr/bin/g++-11",
"args": [
"-fdiagnostics-color=always",
"-g",
// "${file}",
"${workspaceFolder}/exercises/chapter11/ch11_2.cpp",
"${workspaceFolder}/exercises/chapter11/ch11_2_vect.cpp",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger."
}
],
"version": "2.0.0"
}
Inline keyword tells the compiler to consider function for inlining. If the function is small and called frequently, inlining it can lead to
performance improvements because the overhead of a function call is avoided.
Inlining - mean that the code of the function is inserted at the point where the function is called, instead of performing a regular function call.
This can potentially improve performance by avoiding the overhead of a function call, but it might increase the size of the binary file because the
function's code could be inserted in multiple places
Classes
- when
designingaclass, you need to develop apublic interfaceand aprivate implementation.
Is-a Relationship Considerations (Public Inheritance) - str. 772 "C++ Prime Plus"
"You should be guided by the is-a relationship. If your proposed derived class is not a particular
kind of the base class, you shouldn’t use public derivation. For example, you
shouldn’t derive a Programmer class from a Brain class. If you want to represent the belief
that a programmer has a brain, you should use a Brain class object as a member of the
Programmer class."
Inheritance
- "Private inheritance limits the use of base-class methods to within derived-class methods" page 800.
STL Iterators
Constant-time complexity operations:
Optional Sequence Requirements:
| Expression | Return Type | Meaning | Container |
|---|---|---|---|
| a.front() | T& | *a.begin() | vector, list, deque |
| a.back() | T& | *--a.end() | vector, list, deque |
| a.push_front(t) | void | a.insert(a.begin(), t) | list, deque |
| a.push_back(t) | void | a.insert(a.end(), t) | vector, list, deque |
| a.pop_front(t) | void | a.erase(a.begin()) | list, deque |
| a.pop_back(t) | void | a.erase(--a.end()) | vector, list, deque |
| a[n] | T& | *(a.begin() + n) | vector, deque |
| a.at(n) | T& | *(a.begin() + n) | vector, deque |
rvalue, lvalue and std::move semantics (transfer ownership of the data)
" The traditional C++ reference, now called an lvalue reference, binds an identifier to an lvalue. An lvalue is an expression, such as a variable name or a dereferenced pointer, that represents data for which the program can obtain an address ... C++11 adds the rvalue reference, indicated by using &&, that can bind to rvalues—that is, values that can appear on the right-hand side of an assignment expression but for which one cannot apply the address operator." - str. 1162 "C++ Prime Plus.
string one("din"); // C-style string constructor
string two(one); // copy constructor – one is an lvalue
string three(one+two); // move constructor, sum is an rvalue
three = one; // automatic copy assignment
four = one + two; // automatic copy assignment
four = std::move(one); // forced move assignment
move constructor:
Useless::Useless(Useless && f): n(f.n)
{
++ct;
pc = f.pc; // steal address
f.pc = nullptr; // give old object nothing in return
f.n = 0;
}
"...constructor then sets the original pointer to the null pointer
because it is not an error to apply delete [] to the null pointer
This appropriation of ownership often is termed pilfering." - str. 1169 "C++ Prime Plus.
Delegating Constructors
delegation - use of constructor as a part of the definition of another constructor.
class Nots{
...
Nots();
Nots(int, double, std::string);
}
Nots::Nots() : Nots(0, 0.1, "WOW"){...} // delegate
Nots::Nots(int ii, double dd, std::string ss){...}
Miscleanous
Three approaches for passing information to an STL algorithm:
function pointers, functors, and lambdas.
"The tuple header file supports the tuple template.A tuple object is a generalization
of a pair object. Whereas a pair object can hold two values whose types need not be the
same, a tuple can hold an arbitrary number of items of different types.
The compile-time rational arithmetic library, supported by the ratio header file,
allows the exact representation of any rational number whose numerator and denominator
can be represented by the widest integer type. It also provides arithmetic operations
for these numbers.
One of the most interesting additions is a regular expression library, supported by the
regex header file.A regular expression specifies a pattern that can be used to match contents
in a text string. For example, a bracket expression matches any single character in
the brackets.Thus, [cCkK] matches a single c, C, k, or K, and [cCkK]at matches the words
cat, Cat, kat, and Kat. Other patterns include \d for a digit, \w for a word, \t for a tab,
and many, many others.The fact that a backslash has a special meaning in C++ as the first
character in an escape sequence requires a pattern like \d\t\w\d (that is, digit-tab-worddigit)
to be written as the string literal "\d\t\w\d", using \ to represent .This is
one reason the raw string was introduced (see Chapter 4); it enables you to write the
same pattern as R"\d\t\w\t".
Unix utilities such as ed, grep, and awk used regular expressions, and the interpreted
language Perl extended their capabilities.The C++ regular expressions library allows you
to choose from several flavors of regular expressions. " - str. 1203 "C++ Prime Plus.
metaprogramming - creating programs that create or modify other programs or even themselves (C++ this can be done during compile time using templates.)